În acest laborator ne propunem să definitivăm conceptele învățate pe parcursul semestrului, reamintindu-ne etapele prin care am trecut în construirea UAL-ului și miniprocesorului nostru. Recapitularea va fi făcută sub forma unui joc pe echipe. Va exista un număr prestabilit de taskuri (întrebări sau cerințe), iar echipa care va răspunde corect prima va primi punctajul pe acea întrebare. La final, punctajul se va împărți între echipe, conform numărului de taskuri la care a răspuns în mod corect fiecare.
Acestea vor fi făcute publice de asistent în timpul laboratorului, unul câte unul. Dacă taskul implică scriere de cod, acesta va fi verificat în simulator de către toți studenții înainte de trecerea la exercițiul următor.
Completați individual formularul de Feedback.
Avem următorul modul definit (un mux 2:1):
module mux2to1 (input [1:0] in, input sel, output out); assign out = in[sel]; endmodule
Creați un modul care să reprezinte un mux 4:1 folosindu-vă de declarări repetate ale modului mux2to1.
Este implementat bine următorul modul? Dacă nu de ce? MyAnd este o poartă and, iar MyUal este un mini-ual care pentru sel == 0 face and pe intrări, iar pentru 1 face or.
module MyAnd(input a, input b, output c) assign c = a & b; endmodule
module MyAnd (input a, input b, output c); reg regc; always @(*) begin regc = a & b; end assign c = regc; end
module MyAnd(input a, input b, output c); if (a == 1 & b == 1) begin c = 1; end else begin c = 0; end endmodule
module MyUal(input a, input b, input sel, output out); always @(*) begin if (sel == 0) begin and(c,a,b); end else begin or(c,a,b); end end endmodule
module MyUal(input a, input b, input sel, output out); always @(*) begin if (sel == 0) begin assign out = a & b; end else begin assign out = a | b; end end endmodule
module MyUal(input a, input b, input sel, output out); always @(*) begin if (sel == 0) begin out = a & b; end else begin out = a | b; end end endmodule
module MyUal(input a, input b, input sel, output out); reg rego; always @(*) begin rego <= a & b; if (sel == 1) begin rego <= a | b; end end assign out = rego; endmodule
module MyUal(input a, input b, input sel, output out); reg rego; always @(*) begin rego = a & b; if (sel == 1) begin rego = a | b; end end assign out = rego; endmodule
module MyUal(input a, input b, input sel, output out); reg rego; always @(*) begin assign rego = (sel == 0) ? a & b : a | b; end assign out = rego; endmodule
module MyAnd(input[3:0] a, input[3:0] b, output[3:0] c); and(c, a, b); endmodule
Care dintre următoarele secvenţe de cod sunt greșite? De ce?
module MyAndXor(input a, input b, output oand, output oxor); assign oand = a & b; assign oxor = a ^ b; endmodule
MyMod face operatia a ^ (a & b).
module Mymod(input a, input b, output c); wire o1; MyAndXor (a, b, o1); MyAndXor(.oxor(c), .a(a), .b(o1)); endmodule
module Mymod(input a, input b, output c); wire o1, o2; MyAndXor m1 (.a(a), .oand(o1), .oxor(o2)); MyAndXor m2 (o1, a, o2, c); endmodule
module Mymod(input a, input b, output c); reg o1, o2; MyAndXor m1 (.a(a), .b(b), .oand(o1)); MyAndXor m2 (o1, a, o2, c); endmodule
Este vreo diferență între comportamentele următoarelor module?
module mux2to1 (input [1:0] in, input sel, output out); wire notsel, and1, and2; not(notsel, sel); and(and1, in[0], notsel); and(and2, in[1], sel); or(out, and1, and2); endmodule
module mux2to1 (input [1:0] in, input sel, output out); assign out = (sel == 0) ? in[0] : in[1]; endmodule
module mux2to1 (input [1:0] in, input sel, output out); reg rego; always @(*) begin case (sel) 1’b0: rego =in[0]; 1’b1: rego =in[1]; default rego = 1’bx; endcase end assign out = rego; endmodule
Este vreo diferență între comportamentele următoarelor module?
module Mymod(input a, input b, output c); reg op1, op2; initial begin op1 = 0; op2 = 0; end always @(*) begin op1 = a & b; op2 = a ^ op1; end assign c = op2; endmodule
module Mymod(input a, input b, output c); reg op1, op2; initial begin op1 = 0; op2 = 0; end always @(*) begin op1 <= a & b; op2 <= a ^ op1; end assign c = op2; endmodule
module Mymod(input a, input b, output c); assign c = a ^ (a & b); endmodule
module Mymod(input a, input b, output c); reg op1, op2; initial begin op1 = 0; op2 = 0; end always @(a,b) begin op1 = a & b; op2 = a ^ op1; end assign c = op2; endmodule
Creați un debouncer în Verilog.
Faceți un automat Moore pentru următorul fsm implementat în Verilog:
`timescale 1ns / 1ps module fsm( input clk, input reset, input in, output out ); reg [1:0] currentState; reg [1:0] nextState; localparam STATE_Initial = 2'd0, STATE_1 = 2'd1, STATE_2 = 2'd2, STATE_3 = 2'd3; assign out = (currentState == STATE_3); always@ ( posedge clk ) begin if ( reset ) currentState <= STATE_Initial; else currentState <= nextState; end end always@ ( * ) begin nextState = currentState; case ( currentState ) STATE_Initial : begin if(in == 0) begin nextState = STATE_1; end else begin nextState = STATE_2; end end STATE_1 : begin if(in == 0) begin nextState = STATE_1; end else begin nextState = STATE_2; end end STATE_2 : begin if(in == 0) begin nextState = STATE_2; end else begin nextState = STATE_3; end end STATE_3 : begin if(in == 0) begin nextState = STATE_1; end else begin nextState = STATE_2; end end default: begin nextState = STATE_Initial; end endcase end endmodule
Este următorul modul o implementare corectă al unui sumator ripple carry? Modulul FullAdder este implementat corect și face ce îi spune numele.
module RippleCarry( input[7:0] A, input[7:0] B, input Cin, output[7:0] S, output Cout ); wire[6:0] C; FullAdder fa0(.A(A[0]),.B(B[0]),.Cin(Cin),.S(S[0]),.Cout(C[0])); FullAdder fa4(.A(A[4]),.B(B[4]),.Cin(C[3]),.S(S[4]),.Cout(C[4])); FullAdder fa5(.A(A[5]),.B(B[5]),.Cin(C[4]),.S(S[5]),.Cout(C[5])); FullAdder fa6(.A(A[6]),.B(B[6]),.Cin(C[5]),.S(S[6]),.Cout(C[6])); FullAdder fa1(.A(A[1]),.B(B[1]),.Cin(C[0]),.S(S[1]),.Cout(C[1])); FullAdder fa2(.A(A[2]),.B(B[2]),.Cin(C[1]),.S(S[2]),.Cout(C[2])); FullAdder fa3(.A(A[3]),.B(B[3]),.Cin(C[2]),.S(S[3]),.Cout(C[3])); FullAdder fa7(.A(A[7]),.B(B[7]),.Cin(C[6]),.S(S[7]),.Cout(Cout)); endmodule
Este implementat corect următorul modul de FullAdder?
module FullAdder( input A, input B, input Cin, output S, output Cout ); wire S1, C1, C2; HalfAdder ha1(.A(A),.B(B),.S(S1),.C(C1)); HalfAdder ha2(.A(S1),.B(Cin),.S(S),.C(C2)); xor(Cout, C1, C2); endmodule
Este implementat corect următorul modul de HalfAdder?
module HalfAdder( input A, input B, output S, output C ); assign S = A | B; assign C = A & B; endmodule
Este implementat corect următorul modul de scăzător?
module Scazator( input[7:0] A, input[7:0] B, output[7:0] D, output Neg ); wire Cout; Exercitiu_2_RippleCarry rc(.A(A),.B(~B),.Cin(1),.S(D),.Cout(Cout)); assign Neg = D[7]; endmodule
Este bine implementat următorul modul de FullAdder pentru CarryLookAhead?
module FullAdder( input A, input B, input Cin, output S, output P, output G ); wire S1, C1, C2; HalfAdder ha1(.A(A),.B(B),.S(S1)); HalfAdder ha2(.A(S1),.B(Cin),.S(S)); assign P = A | B; assign G = A ^ B; endmodule
Care din implementările următoare ale operației MUL sunt corecte?
module POARTA_MUL( input[3:0] A, input[3:0] B, output[7:0] out ); reg[8:0] P; reg[8:0] Aux; reg[8:0] S; reg[3:0] negA; reg var_aux; integer i; always @(*) begin P = {4'b0000, B, 1'b0}; negA = ~A + 1; Aux = {A, 5'b00000}; S = {negA, 5'b00000}; for (i = 0; i < 4; i = i + 1) begin case (P[1:0]) 2'b00: begin end 2'b01: begin P = P + Aux; end 2'b10: begin P = P + S; end 2'b11: begin end endcase var_aux = P[8]; P = P >> 1; P[8] = var_aux; end end assign out = P[8:1]; endmodule
module POARTA_MUL( input[3:0] A, input[3:0] B, output[7:0] out ); reg[8:0] P; reg[8:0] Aux; reg[8:0] S; reg[3:0] negA; reg var_aux; integer i; always @(*) begin P = {4'b0000, B, 1'b0}; negA = ~A + 1; Aux = {A, 5'b00000}; S = {negA, 5'b00000}; for (i = 0; i < 4; i = i + 1) begin case (P[1:0]) 2'b00: begin end 2'b01: begin P = P + Aux; end 2'b10: begin P = P + S; end 2'b11: begin end endcase P = P >>> 1; end end assign out = P[8:1]; endmodule
module POARTA_MUL( input[3:0] A, input[3:0] B, output[7:0] out ); reg[8:0] P; reg[8:0] Aux; reg[8:0] S; reg[3:0] negA; reg var_aux; integer i; always @(*) begin P = {4'b0000, B, 1'b0}; negA = ~A + 1; Aux = {A, 5'b00000}; S = {negA, 5'b00000}; for (i = 0; i < 4; i = i + 1) begin case (P[1:0]) 2'b00: begin end 2'b01: begin P = P + Aux; end 2'b10: begin P = P + S; end 2'b11: begin end endcase P = P >> 1; end end assign out = P[8:1]; endmodule
module POARTA_MUL( input[3:0] A, input[3:0] B, output[7:0] out ); reg[8:0] P; reg[8:0] Aux; reg[8:0] S; reg[3:0] negA; reg var_aux; integer i; always @(*) begin P = {4'b0000, B, 1'b0}; negA = ~A + 1; Aux = { 5'b00000, A}; S = {,5'b00000, negA}; for (i = 0; i < 4; i = i + 1) begin case (P[1:0]) 2'b00: begin end 2'b01: begin P = P + Aux; end 2'b10: begin P = P + S; end 2'b11: begin end endcase var_aux = P[8]; P = P >> 1; P[8] = var_aux; end end assign out = P[8:1]; endmodule
module POARTA_MUL( input[3:0] A, input[3:0] B, output[7:0] out ); reg[8:0] P; reg[8:0] Aux; reg[8:0] S; reg[3:0] negA; reg var_aux; integer i; always @(*) begin P = {4'b0000, B, 1'b0}; negA = ~A + 1; Aux = {negA, 5'b00000}; S = {A, 5'b00000}; for (i = 0; i < 4; i = i + 1) begin case (P[1:0]) 2'b00: begin end 2'b01: begin P = P + Aux; end 2'b10: begin P = P + S; end 2'b11: begin end endcase var_aux = P[8]; P = P >> 1; P[8] = var_aux; end end assign out = P[8:1]; endmodule
Care dintre următoarele module implementează corect afișarea cifrei 2 pe un afișaj cu 7 segmente din cadrul plăcuței de la laborator?
module task0( output wire o_w_AN0, output wire o_w_AN1, output wire o_w_AN2, output wire o_w_AN3, output wire o_w_CA, output wire o_w_CB, output wire o_w_CC, output wire o_w_CD, output wire o_w_CE, output wire o_w_CF, output wire o_w_CG, output wire o_w_DP ); assign o_w_AN0 = 0; assign o_w_AN1 = 1; assign o_w_AN2 = 1; assign o_w_AN3 = 1; assign o_w_CA = 0; assign o_w_CB = 0; assign o_w_CC = 1; assign o_w_CD = 0; assign o_w_CE = 0; assign o_w_CF = 1; assign o_w_CG = 0; assign o_w_DP = 1; endmodule
module task0( output wire o_w_AN0, output wire o_w_AN1, output wire o_w_AN2, output wire o_w_AN3, output wire o_w_CA, output wire o_w_CB, output wire o_w_CC, output wire o_w_CD, output wire o_w_CE, output wire o_w_CF, output wire o_w_CG, output wire o_w_DP ); assign o_w_AN0 = 1; assign o_w_AN1 = 1; assign o_w_AN2 = 1; assign o_w_AN3 = 1; assign o_w_CA = 0; assign o_w_CB = 0; assign o_w_CC = 1; assign o_w_CD = 0; assign o_w_CE = 0; assign o_w_CF = 1; assign o_w_CG = 0; assign o_w_DP = 1; endmodule
module task0( output wire o_w_AN0, output wire o_w_AN1, output wire o_w_AN2, output wire o_w_AN3, output wire o_w_CA, output wire o_w_CB, output wire o_w_CC, output wire o_w_CD, output wire o_w_CE, output wire o_w_CF, output wire o_w_CG, output wire o_w_DP ); assign o_w_AN0 = 0; assign o_w_AN1 = 1; assign o_w_AN2 = 1; assign o_w_AN3 = 1; assign o_w_CA = 1; assign o_w_CB = 1; assign o_w_CC = 0; assign o_w_CD = 1; assign o_w_CE = 1; assign o_w_CF = 0; assign o_w_CG = 1; assign o_w_DP = 0; endmodule
module task0( output wire o_w_AN0, output wire o_w_AN1, output wire o_w_AN2, output wire o_w_AN3, output wire o_w_CA, output wire o_w_CB, output wire o_w_CC, output wire o_w_CD, output wire o_w_CE, output wire o_w_CF, output wire o_w_CG, output wire o_w_DP ); assign o_w_AN0 = 1; assign o_w_AN1 = 0; assign o_w_AN2 = 0; assign o_w_AN3 = 0; assign o_w_CA = 1; assign o_w_CB = 1; assign o_w_CC = 0; assign o_w_CD = 1; assign o_w_CE = 1; assign o_w_CF = 0; assign o_w_CG = 1; assign o_w_DP = 0; endmodule
Cum putem afișa 2 valori diferite pe 2 cifre diferite pentru cele 4 afișaje cu 7 segmente din cadrul plăcuței de la laborator?
Descrieți pe scurt conceptul de pipelinening, enumerând prin ce etape trece o instrucțiune. Ce probleme pot apărea în cazul pipelineningului și cum se pot corecta?
Care sunt diferențele dintre circuitele logice combinaționale și cele secventiale?
Ce tipuri de atribuiri pot fi folosite într-un modul Verilog si care sunt diferențele dintre acestea?
Comparați cele 3 tipuri de descriere ale modulelor în Verilog.
Declarați și instanțiați un modul care are:
un port de intrare si iesire data
pe 16 biți cu LSB în stânga;
un port de ieșire valid
pe un bit, de tip registru;
un port de intrare address
pe 8 biți cu MSB în stânga;
un port de intrare write
pe un bit;
un port de intrare row
pe un bit.
Înainte de a îl instanția, declarați și variabilele necesare instanțierii.
Ce valori vor avea x, y, z la finalul secventei următoare de cod, știind că inițial x = 6
, y = 2
, z = 4
și că au lățimea de 3 biti?
x <= x & y; y <= x & z; z <= y ^ x;
Ce valori vor avea x, y, z la finalul secventei următoare de cod, știind că inițial x = 6
, y = 2
, z = 4
și că au lățimea de 3 biti?
x = x & y; y = x & z; z = y ^ x;
Identificati greseliile din următorul modul Verilog.
module mux_4_to_1( output reg out, input in0, input in1, input in2, input in3, input sel0, input sel1 ); always @* case ([sel1, sel0]) 1'b00: out = in0; 2'b01: out = in1; 2'b10: out = in2; 2'b11: out = in3; default: out = 1b’x; end end endmodule
Corectați următorul modul Verilog care contine o intrare de selectie pe 3 biti, 2 intrari a si b pe 2 biti si o iesire tot pe 2 biti. În funcție de selecție, ieșirea va avea următoarele valori:
sel == 1
: se aplică NAND pe cele 2 intrări;sel == 2
: se aplică OR pe cele 2 intrări;sel == 4
: ieșirea modulului random (primul parametru este ieșirea, apoi sunt cele 2 intrări care ar trebui sa fie a și b);module complete_me(output [2:0] out, input [2:0] a, input [2:0] b, input [3:0] sel); wire out_nand; wire out_or; wire out_random; always @(*) begin random(out_random, a, b); end always @(*) begin out_nand <= ~(a & b); out_or = or(a, b); end case(sel) 3’b0: out = out_nand; 3’b1: out = out_or; 3’b2: out = out_random; default: out = 2’bx; endcase endmodule
Secvențele greșite de cod se pot înlocui cu următoarele răspunsuri:
output [2:0] out, input [2:0] a, input [2:0] b, input [3:0] sel
output out, input a, input b, input sel
output [1:0] out, input [1:0] a, input [1:0] b, input [2:0] sel
wire out_nand; reg out_or; wire out_random;
wire out_or; reg out_nand; reg out_random;
reg out_nand; reg out_or; wire out_random;
random(out_random, a, b);
always @(*) begin random rand(out_random, a, b); end
random rand(out_random, a, b);
assign out_nand = ~(a & b);
out_nand = nand(a, b);
nand(a, b);
out_or = or(a, b);
assign out_or = a | b;
or(a, b);
assign out = sel == 3’b001 ? out_nand : 3’b010 ? out_or : 3’b100 ? out_random : 2’bx;
if (sel == 1) out = out_nand; else if (sel == 2) out = out_or; else if (sel == 4) out = out_random; else out = 2’bx; end
if (sel == 3’b0) out = out_nand; else if (sel == 3’b1) out = out_or; else if (sel == 3’b2) out = out_random; else out = 2’bx; end
În vederea pregătirii problemei pentru examen (a.k.a proba numita “problema”), trebuie să aveți în vedere cele 2 mari tipuri de probleme prezentate la curs:
Pentru ambele tipuri de probleme, găsiți teoria necesara în cursul de CN de pe moodle. Pe lângă exemplele din curs, mai jos am atașat câte un model complet de redactare pentru fiecare subiect.
În plus, puteți consulta următoarele link-uri:
Fie următorul cod în assembly (simplificat):
mov ax, $a mov bx, $b _while: cmp ax, bx ; ax ? bx jg _greater ; ax > bx ? jl _less ; ax < bx ? je _pwp ; ax == bx ? jmp _while _greater: sub ax, bx ; ax = ax - bx jmp _while _less: sub bx, ax ; bx = bx - ax jmp _while _pwp: ;se afiseaza conținutul lui ax
jmp
este instrucțiune ce implementează un salt necondiționatjg
, jl
, je
sunt instrucțiuni ce implementează salturi CONDITIONATE (doar pentru acestea Branch Predictorul poate optimiza lucruri)add
/sub
, cmp
sunt folosite pentru adunare/scadere și compararemov
este instrucțiunea care copiază în destinație (primul operand), conținutul sursei (al doilea operand)add
/sub
, je
/jg
/jl
/jmp
, cmp
, inc
, load (ld
) /store (st
)/mov
. De asemenea, ce este un registru (ex. ax
/eax
, bx
/ebx
, cx
/ecx
, dx
/edx
sau r1
, r2
, r3
…), cum luăm valoarea de la o adresa (b
), sintaxa pentru instrucțiuni (ex. mov reg destinație reg_sursa
).
Se știu numărul de cicli de ceas pentru fiecare tip de instrucțiune: mov - 1 ciclu, cmp - 1 ciclu, sub - 1 ciclu, branch - 20 cicli (dacă nu a fost prezis corect) sau 2 cicli (dacă a fost prezis corect), iar frecvența procesorului este de 1GHz.
Se va cere rezolvarea unui subiect asemănător cu unul dintre următoarele:
A. Fie procesorul A care implementează un branch predictor global, iar metoda de branch prediction folosită este 1-bit counter (taken/not taken). Starea inițială este not taken.
B. Fie procesorul B care implementează un branch predictor global, iar metoda de branch prediction folosită este 2-bit counter (strongly taken/weak taken/weak not taken/strongly not taken). Starea inițială este strongly not taken.
C. Fie procesorul C care implementează un branch predictor local, iar metoda de branch prediction folosită este 1-bit counter (taken/not taken). Starea inițială este not taken.
D. Fie procesorul D care implementează un branch predictor local, iar metoda de branch prediction folosită este 2-bit counter (strongly taken/weak taken/weak not taken/strongly not taken). Starea inițială este strongly not taken.
Fie următorul cod în assembly (x86). Indentificați hazardele de date. Pentru fiecare menționați intrucțiunile implicate, arătând cauzele fiecărui hazard.
Treceți hazardele în ordinea crescătoare a instrucțiunilor.
Exemplu: Dacă există:
atunci veți scrie:
Ix - Iy: RAW (eax)
Ix - Iz: RAW (eax)
It - Iz: RAW (eax)
0: mov ebx, edx ; ebx = edx 1: add ecx, ebx ; ecx = ecx + ebx 2: mov eax, [0xCAFEBABE] ; eax = MEM[0xCAFEBABE] 3: mov edx, eax ; edx = eax 4: xor edi, eax ; edi = edi ^ eax
Colocviul va fi dat pe 22 mai 2024 in PR001 in intervalul orar 16-18(in timpul cursului de SOC). Regulamentul se află aici.
Puteți să consultați, pentru a vă familiariza cu formatul, Modelul de test practic. si Tutorial Virtual Programing Lab
Formatul acestuia va fi următorul: