/***************************************************************** VeriLab 3 MEMORIES: LATCHES, FLIP-FLOPS, REGISTERS, RANDOM ACCESS MEMORIES ******************************************************************/ /* To memorise means to mentain a state induced by a previously activated signal. Instead of the previous signal there must be another signal. This signal could be obtined closing a loop over small and simple digital circuits, thus generating elements of 1-OS. The elementary latch will be built loop connecting NANDs or NORs. The memory implies the time. The time manifests inside of digital systems in a discret form as clock: a signal switching ritmicaly from one to zero and from zero to one. The clock allows us to declutch the 'how' by 'when'. Therefore, there are inputs on which we apply the signal meaning about how the circuit will switches and there is another inputs on which we apply the clock, indicating the moment of the switching. Thus, the ckocked circuits occure inside the world of digital circuits. There are two kinds of memory circuits: - the transparent memories - on the active level of the clock the input switches act on the outputs - the non-transparent memories - with outputs switching only sinchronized by the active edge of the clock (positive edge or negative edge). The transparency is avoided using the master-slave principle which involves to compose, by serial connection, two transparent structures one clocked with the clock and the other clocked with the inverted clock. The composition by parallel connection leds to the random acces memory - a transparent big storage structure. The serial-parallel composition, using elementary latches, allows the building of the most important component of the complex structures - the register. The register allows the closing of the next loop in order to reach the level of 2-OS. */ /*************** PROBLEM NO.1: The unstable loop: a three (odd) inverting level loop The module is used to show the effect of a loop closed through a loop containig three inverting levels. The behavior is similar for any other odd number of inverting levels.*/ /* module wave_gen(out); // the output of the circuit switches with constant input and without // clock signal output out; reg enable; // a value that close (enable = 1) or open (enable = 0) the three inverting // level loop wire w1, w2; initial begin enable = 0; #15 enable = 1; #50 enable = 0; #15 $stop; // stops the simulation end nand #1 (out, enable, w2); // a two input circuit allowing the comand of the loop to be // open or closed not #1 inv_1(w1, out), inv_2(w2, w1); // an even number of gates can be added and the behaviour remains // the same, excepting the frequency of the oscilating process initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.2: The stable loop: elementary latch built with two loop-connected NANDs */ /* module latch(q, nq, ns, nr); input ns, // active low set input, the output q becomes 1 and the output nq becomes 0 nr; // active low reset input, the output nq becomes 1 and the output q becomes 1 output q, nq; // the two outputs, having, in the usual functioning (!), inverted values nand #1 gate_1(q, nq, ns); // try with x = #4 nand #1 gate_0(nq, q, nr); // try with x = #4 // The outputs of each the two gates are connected to the one input of the other gate, i.e., // the loop is closed through two (even) levels of inverted gate. endmodule module test_latch; reg ns, nr; wire q, nq; initial #60 $stop; initial begin ns = 0; nr = 0; #10 ns = 1; // will behaves like a rectangular wave generator: because of the nr = 1; // perfect simetry the loop works like a one inverted level loop #20 ns = 0; #2 ns = 1; // try with y = #1 #10 nr = 0; #2 nr = 1; // try with y = #1 end // could be make interesting experiments using different values for x and y latch dut(q, nq, ns, nr); initial $monitor("timp=%0d ns=%b nr=%b q=%b nq=%b", $time, ns, nr, q, nq); initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.3: Elementary latch built with two loop-connected NORs (proposed to be done) */ /* module latch_nor(q, nq, s, r); endmodule */ /*************** PROBLEM NO.4: The clocked latch */ /* module clocked_latch(q, nq, s, r, ck); input s, // set input, 'tells' the latch to switces in q = 1, when the clock becomes active r, // reset input, 'tells' the latch to switces in q = 0, when the clock becomes active ck; // clock input, is active on the high level (ck = 1), when the output follows the inputs // 's' and 'r'. Attention! s = r =1 generate an unstable behaviour at the end of the // active level of ck if the circuit has a perfect symmetry. output q, nq; wire w1, w2; nand #1 gate_3(q, nq, w1), gate_2(nq, q, w2), // the first two gates form the latch gate_1(w1, s, ck), gate_0(w2, r, ck); // the last two gates allow the applying of the clock signal endmodule module test_clocked_latch; reg s, r, ck; initial begin ck = 0; forever #10 ck = ~ck; end initial begin {s, r} = 2'b0; #40 s = 1; #20 s = 0; #60 r = 1; #20 r = 0; #10 $stop; end clocked_latch latch(q, nq, s, r, ck); initial $vw_dumpvars; // must to be emphasized the transparency of the circuit on the active level of the clock endmodule */ /*************** PROBLEM NO.5: The master-slave principle */ ///* module master_slave(q, nq, set, reset, clock); input set, reset, clock; output q, nq; wire inv_ck, master_q, master_nq; // The master-slave structure. clocked_latch master_latch(master_q, master_nq, set, reset, inv_ck), slave_latch(q, nq, master_q, master_nq, clock); // The inverter which avoid the transparency not #1 clock_inverter(inv_ck, clock); endmodule module clocked_latch(q, nq, s, r, ck); // previously designed input s, r, ck; output q, nq; wire w1, w2; nand #1 gate_3(q, nq, w1), gate_2(nq, q, w2), gate_1(w1, s, ck), gate_0(w2, r, ck); endmodule module test_master_slave; reg set, reset, clock; initial begin clock = 0; forever #10 clock = ~clock; end initial begin {set, reset} = 2'b0; #20 {set, reset} = 2'b10; #40 {set, reset} = 2'b00; #40 {set, reset} = 2'b01; #20 {set, reset} = 2'b00; #60 {set, reset} = 2'b11; // explain the behaviour that follows! #60 {set, reset} = 2'b00; #20 {set, reset} = 2'b10; #60 $stop; end master_slave our_flip_flop(q, nq, set, reset, clock); initial $vw_dumpvars; endmodule //*/ /*************** PROBLEM NO.6: D (delay) flip-flop */ /* module d_flip_flop(q, nq, d, clock); input d, clock; output q, nq; master_slave r_s_flip_flop(q, nq, d, nd, clock); not #1 d_inverter(nd, d); // avoids the possibility of 's = r = 1' endmodule module master_slave(q, nq, set, reset, clock); // defined in the previous problem input set, reset, clock; output q, nq; wire inv_ck, master_q, master_nq; clocked_latch master_latch(master_q, master_nq, set, reset, inv_ck), slave_latch(q, nq, master_q, master_nq, clock); not clock_inverter(inv_ck, clock); endmodule module clocked_latch(q, nq, s, r, ck); input s, r, ck; output q, nq; wire w1, w2; nand #1 gate_3(q, nq, w1), gate_2(nq, q, w2), gate_1(w1, s, ck), gate_0(w2, r, ck); endmodule module test_d_flip_flop; reg d, clock; initial begin clock = 0; forever #10 clock = ~clock; end initial begin d = 0; #110 d = 1; #60 d = 0; #120 d = 1; #40 d = 0; #80 d = 1; #60 $stop; end d_flip_flop our_d_flip_flop(q, nq, d, clock); initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.7: D flip-flop with asynchronous set and reset (to be done structurally) */ /* module presetable_d_flip_flop(q, nq, d, clock, set, reset); input d, clock, set, // works asynchronously at the level of the slave latch reset; // works asynchronously at the level of the slave latch output q, nq; endmodule */ /*************** PROBLEM NO.8: The behavioral description of D flip-flop with asynchronous reset */ /* module presetable_D_ff(q, nq, d, enable, clock, reset); input d, enable, clock, reset; output q, nq; reg q; always @(posedge clock or reset) if (reset) #1 q = 0; // the delay is only #1 because 'reset' acts on slave latch else if (enable) #2 q = d; // the delay is #2 because the switch involve all the structure assign #1 nq = ~q; endmodule module test_D_ff; reg d, enable, clock, reset; initial begin clock = 0; forever #5 clock = ~clock; end initial begin {d, enable, reset} = 3'b000; #110 {d, enable, reset} = 3'b001; #60 {d, enable, reset} = 3'b000; #120 {d, enable, reset} = 3'b110; #40 {d, enable, reset} = 3'b010; #80 {d, enable, reset} = 3'b110; #80 {d, enable, reset} = 3'b000; #80 {d, enable, reset} = 3'b000; #80 {d, enable, reset} = 3'b010; #60 $stop; end presetable_D_ff our_D_ff(q, nq, d, enable, clock, reset); initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.9: 4-bit register structurally described */ /* module register_4(out, in, enable, clock, reset); input enable, clock, reset; input[3:0] in; output[3:0] out; // 4 D flip-flops composed in parallel (the outputs 'nq' are not used) presetable_D_ff ff_3(out[3], nq, in[3], enable, clock, reset), ff_2(out[2], nq, in[2], enable, clock, reset), ff_1(out[1], nq, in[1], enable, clock, reset), ff_0(out[0], nq, in[0], enable, clock, reset); endmodule module presetable_D_ff(q, nq, d, enable, clock, reset); input d, enable, clock, reset; output q, nq; reg q; always @(posedge clock or reset) if (reset) #1 q = 0; else if (enable) #2 q = d; assign #1 nq = ~q; endmodule module test_reg_4; reg enable, clock, reset; reg[3:0] counter; wire[3:0] out; initial begin clock = 0; counter = 0; forever #5 clock = ~clock; end always @(negedge clock) counter = counter + 1; initial begin {enable, reset} = 2'b00; #22 {enable, reset} = 3'b01; #38 {enable, reset} = 3'b00; #130 {enable, reset} = 3'b10; #130 {enable, reset} = 3'b00; #130 {enable, reset} = 3'b10; #60 $stop; end register_4 reg_under_test(out, counter, enable, clock, reset); initial $vw_dumpvars; endmodule */ /**************** PROBLEM NO.10: The behavioral description of the n-bit register with synchronous reset */ /* module n_bit_reg(out, in, enable, clock, reset); parameter word_dim = 8; input enable, clock, reset; input[word_dim - 1:0] in; output[word_dim - 1:0] out; reg[word_dim - 1:0] out; // reprezents a register, not only a variable! always @(posedge clock) if (reset) out = 0; else if (enable) out = in; endmodule module test_register; parameter word_dim = 8; reg enable, clock, reset; reg[word_dim - 1:0] counter; wire[word_dim - 1:0] out; initial begin clock = 0; counter = 0; forever #5 clock = ~clock; end always @(negedge clock) counter = counter + 1; initial begin {enable, reset} = 2'b00; #22 {enable, reset} = 3'b01; #38 {enable, reset} = 3'b00; #130 {enable, reset} = 3'b10; #130 {enable, reset} = 3'b00; #130 {enable, reset} = 3'b10; #60 $stop; end n_bit_reg register(out, counter, enable, clock, reset); initial $vw_dumpvars; endmodule */ /**************** PROBLEM NO.11: Static random access memory (SRAM) */ /* module mem(dout, din, address, write); parameter word_dim = 16, add_dim = 8; input write; // write command, active high input[word_dim - 1:0] din; // data input to be written to the address 'address' input[add_dim - 1:0] address; // the input indicating the address to be accessed // for write or/and read output[word_dim - 1:0] dout; // data output which will follow continouslly the // content of the accessed location // The memory, consists in an array of 'word_dim'-bit latches reg[word_dim - 1:0] memory[0:(1'b1 << add_dim) - 1]; // The read operation is a continous assingned action assign dout = memory[address]; // The write operation acts only if 'write = 1'. It is compulsory that the address be // stable when 'write' is active. Data can be change but must be stable a set-up time before // 'write' ends always @(address or din or write) if (write) memory[address] = din; endmodule module test_mem; parameter word_dim = 16, add_dim = 8; reg write; reg[word_dim - 1:0] din; reg[add_dim - 1:0] address; wire[word_dim - 1:0] dout; initial begin address = 0; write = 0; din = 16'b0100111110100001; // memory_content.v is a file containig the initial values stored in memory $readmemb("memory_content.v", under_test_memory.memory); #1 address = address + 1; #1 address = address + 1; #1 address = address + 1; #1 address = address + 1; #1 write = 1; #1 write = 0; #1 din = 16'b1111111110100001; #1 write = 1; #1 din = 16'b10100001; #1 write = 0; #4 $stop; end mem under_test_memory(dout, din, address, write); initial $monitor("time=%0d add=%b din=%b write=%b dout=%b", $time, address, din, write, under_test_memory.dout); initial $vw_dumpvars; endmodule */ /**************** PROBLEM NO.12: Multi-port memory */ /* // This will be a multiport memory, with two output port and one input port. Three distinct // accesses can be done simultaneously, one for write and two for read. module multi_port_mem(left_out, right_out, din, dest_add, left_add, right_add, write); parameter word_dim = 16, add_dim = 8; input write; input[word_dim - 1:0] din; input[add_dim - 1:0] dest_add, // the write address left_add, // the read address for the left outputs right_add; // the read address for the right outputs // Two word are read simultaneously from this memory output[word_dim - 1:0] left_out, // the left output right_out; // the right output reg[word_dim - 1:0] memory[0:(1'b1 << add_dim) - 1]; assign left_out = memory[left_add], right_out = memory[right_add]; always @(dest_add or din or write) if (write) memory[dest_add] = din; endmodule module test_multi_port_memory; parameter word_dim = 16, add_dim = 8; reg write; reg[word_dim - 1:0] din; reg[add_dim - 1:0] dest_add, left_add, right_add; wire[word_dim - 1:0] left_out, right_out; initial begin dest_add = 0; left_add = 0; right_add = 0; din = 16'b0100111110100001; write = 0; $readmemb("memory_content.v", dut.memory); #1 left_add = left_add + 1; #1 right_add = right_add + 1; #1 left_add = left_add + 1; #1 left_add = left_add + 1; #1 write = 1; #1 write = 0; dest_add = dest_add + 1; #1 din = 16'b1111111110100001; #1 write = 1; #1 din = 16'b10100001; #1 write = 0; #4 $stop; end multi_port_mem dut(left_out, right_out, din, dest_add, left_add, right_add, write); initial $vw_dumpvars; endmodule */