Development Environment.
Program : Quartus Prime 18.1 Lite Edition
Tool : Modelsim 10.5b Starter Edition
FPGA : MAX10
Language: Verilog2001
Objective.
Design an 8-bit Multiplier module in Verilog and verify the results through simulation.
Why?
ALU는 CPU 내부에서 가장 기본이 되는 설계 블록이다. 컨트롤 유닛으로부터 명령을 받아 CPU로 들어온 모든 데이터들의 산술,논리 연산을 담당한다. 8-Bit Multiplier를 먼저 설계함으로써 ALU와 같은 연산 장치 내에서 데이터의 처리와 연산 과정이 어떻게 진행되는지 파악함과 동시에 하드웨어 설계 및 프로그래밍에 대한 이해를 넓히고자 한다.
Design Steps.
1. Design overview.
2. Block Diagram.
3. Design Block & Verilog Coding.
4. Simulation.
1. Design overview.
8-Bit Multiplier를 설계함에 있어 4-Bit Multiplier 모듈을 재사용하고 Finite State Machine 방식을 채택하도록 하겠다. 모듈의 재사용을 통해 8-Bit Multiplier 대비 논리 게이트의 갯수와 회로의 사이즈를 줄여 하드웨어 리소스를 절약할 수 있고 코드의 일관성을 유지할 수 있다. 또한, 이미 구현된 모듈을 활용하여 개발 시간을 단축하고 테스트 및 검증 측면에서도 신뢰성을 향상시킬 수 있다.
FSM(Finite State Machine, 유한 상태 기계)은 유한한 수의 상태를 가지는 수학적 모델로 상태(State)들 간의 전이(Transition)에 의해 출력을 생성하는 회로를 총칭한다. 반드시 하나의 상태만을 가지며 현재 상태(Current State)에서 특정한 입력(Event)이 발생하면 다음 상태(Next State)로 전이(Transition)하며 출력을 결정한다. FSM은 각 상태에서 어떤 동작이 수행되는지를 명확하게 정의하기 때문에 시스템의 동작이 직관적이고 예측 가능하다는 특징이 있다. 그렇기 때문에 오류가 발생하더라도 쉽게 수정이 가능하며 각 상태의 동작을 시각화하여 표현함으로써 복잡한 시스템의 구조 및 동작 이해가 가능하게 된다.
2. Block Diagram.
3. Design Block.
(1) Operation Block (Mux4, Mult4, shifter, adder, reg16)
module mux4 (
input [3:0] mux_in_a ,
input [3:0] mux_in_b ,
input sel ,
output reg [3:0] mux_out
);
always@(*) begin
if(sel == 0)
mux_out = mux_in_a;
else
mux_out = mux_in_b;
end
endmodule
module mult4 (
input [3:0] dataa ,
input [3:0] datab ,
output [7:0] product
);
assign product = dataa * datab;
endmodule
module shifter (
input [ 7:0] inp ,
input [ 1:0] shift_ctrl ,
output reg [15:0] shift_out
);
always@(*) begin
if(shift_ctrl == 1)
shift_out = {4'b0, inp, 4'b0};
else if(shift_ctrl == 2)
shift_out = {inp, 8'b0};
else
shift_out = {8'b0, inp};
end
endmodule
module adder16 (
input [15:0] dataa,
input [15:0] datab,
output [15:0] sum
);
assign sum = dataa + datab;
endmodule
module reg16 (
input clk ,
input sclr_n ,
input clk_ena ,
input [15:0] datain ,
output reg [15:0] reg_out
);
always@(posedge clk) begin
if(clk_ena)
if(!sclr_n)
reg_out <= 0;
else
reg_out <= datain;
end
endmodule
(2) Control Block (Counter, Mult8_ctrl, 7SEGMENT)
module counter (
input clk ,
input clr_n ,
output reg [1:0] count_out
);
always@(posedge clk, negedge clr_n) begin
if(!clr_n)
count_out <= 0;
else
count_out <= count_out + 2'b1;
end
endmodule
설계한 카운터로 LSB, MID1, MID2, MSB 상태를 제어하고 start 신호로 연산의 시작과 끝을 제어한다.
module mult8_ctrl (
input clk ,
input reset_a ,
input start ,
input [1:0] count ,
output reg [1:0] input_sel,
output reg [1:0] shift_sel,
output reg [2:0] state_out,
output reg done ,
output reg clk_ena ,
output reg sclr_n
);
parameter IDLE = 0;
parameter LSB = 1;
parameter MID = 2;
parameter MSB = 3;
parameter CALC_DONE = 4;
parameter ERR = 5;
reg [2:0] cst = 0;
reg [2:0] nst;
always@(posedge clk, posedge reset_a) begin
if(reset_a)
cst <= IDLE;
else
cst <= nst;
end
always@(*) begin
case(cst)
IDLE:
if(start)
nst = LSB;
else
nst = IDLE;
LSB:
if(start == 0 && count == 0)
nst = MID;
else
nst = ERR;
MID:
if(start == 0 && count == 2)
nst = MSB;
else if(start == 0 && count == 1)
nst = MID;
else
nst = ERR;
MSB:
if(start == 0 && count == 3)
nst = CALC_DONE;
else
nst = ERR;
CALC_DONE:
if(!start)
nst = IDLE;
else
nst = ERR;
ERR:
if(start)
nst = LSB;
else
nst = ERR;
endcase
end
always@(*) begin
input_sel = 2'bxx;
shift_sel = 2'bxx;
done = 1'b0;
clk_ena = 1'b0;
sclr_n = 1'b1;
case(cst)
IDLE:
if(start) begin
clk_ena = 1'b1;
sclr_n = 1'b0;
end
LSB:
if(start == 0 && count == 0) begin
input_sel = 2'd0;
shift_sel = 2'd0;
clk_ena = 1'b1;
end
MID:
if(start == 0 && count == 2) begin
input_sel = 2'd2;
shift_sel = 2'd1;
clk_ena = 1'b1;
end
else if (count == 1 && start == 0) begin
input_sel = 2'd1;
shift_sel = 2'd1;
clk_ena = 1'b1;
end
MSB:
if (count == 3 && start == 0) begin
input_sel = 2'd3;
shift_sel = 2'd2;
clk_ena = 1'b1;
end
CALC_DONE:
if (!start)
done = 1'b1;
ERR:
if (start) begin
clk_ena = 1'b1;
sclr_n = 1'b0;
end
endcase
end
always@(*) begin
state_out = 3'b0;
case(cst)
IDLE : state_out = 3'b000;
LSB : state_out = 3'b001;
MID : state_out = 3'b010;
LSB : state_out = 3'b011;
CALC_DONE: state_out = 3'b100;
ERR : state_out = 3'b101;
endcase
end
endmodule
module seven_segment_ctrl (
input [2:0] inp ,
output reg seg_a ,
output reg seg_b ,
output reg seg_c ,
output reg seg_d ,
output reg seg_e ,
output reg seg_f ,
output reg seg_g
);
always@(*) begin
case(inp)
3'b000 : {seg_a,seg_b,seg_c,seg_d,seg_e,seg_f,seg_g} = ~7'b1111110;
3'b001 : {seg_a,seg_b,seg_c,seg_d,seg_e,seg_f,seg_g} = ~7'b0110000;
3'b010 : {seg_a,seg_b,seg_c,seg_d,seg_e,seg_f,seg_g} = ~7'b1111001;
3'b011 : {seg_a,seg_b,seg_c,seg_d,seg_e,seg_f,seg_g} = ~7'b1111001;
default : {seg_a,seg_b,seg_c,seg_d,seg_e,seg_f,seg_g} = ~7'b1001111;
endcase
end
endmodule
8-bit Multiplier Verilog Coding.
module mult8 (
input clk ,
input reset_a ,
input start ,
input [ 7:0] dataa ,
input [ 7:0] datab ,
output done_flag ,
output [15:0] product8x8_out ,
output seg_a ,
output seg_b ,
output seg_c ,
output seg_d ,
output seg_e ,
output seg_f ,
output seg_g
);
wire [1:0] w_count;
wire [1:0] w_inputsel;
wire [1:0] w_shiftsel;
wire [3:0] w_aout;
wire [3:0] w_bout;
wire [7:0] w_product4x4;
wire [15:0] w_shiftout;
wire [15:0] w_sum;
wire w_sclr;
wire w_clken;
wire [2:0] w_stateout;
mult8_ctrl uMult8_ctrl_0 (
.clk (clk ),
.reset_a (reset_a ),
.start (start ),
.count (w_count ),
.input_sel(w_inputsel),
.shift_sel(w_shiftsel),
.state_out(w_stateout),
.done (done_flag ),
.clk_ena (w_clken ),
.sclr_n (w_sclr )
);
mux4 uMux4_0 (
.mux_in_a(dataa[3:0] ),
.mux_in_b(dataa[7:4] ),
.sel (w_inputsel[1] ),
.mux_out (w_aout )
);
mux4 uMux4_1 (
.mux_in_a(datab[3:0] ),
.mux_in_b(datab[7:4] ),
.sel (w_inputsel[0] ),
.mux_out (w_bout )
);
mult4 uMult4_0 (
.dataa (w_aout ),
.datab (w_bout ),
.product(w_product4x4)
);
counter uCounter_0(
.clk (clk ),
.clr_n (!start ),
.count_out(w_count)
);
shifter uShifter_0 (
.inp (w_product4x4 ),
.shift_ctrl (w_shiftsel ),
.shift_out (w_shiftout )
);
adder16 uAdder16_0 (
.dataa(w_shiftout ),
.datab(product8x8_out),
.sum (w_sum )
);
reg16 uReg16_0 (
.clk (clk ),
.sclr_n (w_sclr ),
.clk_ena(w_clken ),
.datain (w_sum ),
.reg_out(product8x8_out )
);
seven_segment_ctrl uSeven_segment_ctrl_0 (
.inp (w_stateout),
.seg_a(seg_a),
.seg_b(seg_b),
.seg_c(seg_c),
.seg_d(seg_d),
.seg_e(seg_e),
.seg_f(seg_f),
.seg_g(seg_g)
);
endmodule
4. Simulation.
`timescale 1 ns / 1 ns
`define CLOCK 50
module tb_mult8();
reg clk ;
reg reset_a ;
reg start ;
reg [ 7:0] dataa ;
reg [ 7:0] datab ;
wire done_flag ;
wire [15:0] product8x8_out ;
wire seg_a ;
wire seg_b ;
wire seg_c ;
wire seg_d ;
wire seg_e ;
wire seg_f ;
wire seg_g ;
mult8 mult8_u0(
.clk (clk ),
.reset_a (reset_a ),
.start (start ),
.dataa (dataa ),
.datab (datab ),
.done_flag (done_flag ),
.product8x8_out(product8x8_out),
.seg_a (seg_a ),
.seg_b (seg_b ),
.seg_c (seg_c ),
.seg_d (seg_d ),
.seg_e (seg_e ),
.seg_f (seg_f ),
.seg_g (seg_g )
);
initial fork
clk_gen();
reset_gen();
start_gen();
data_gen();
join
task clk_gen;
begin
clk = 1'b0;
forever clk = #(`CLOCK/2) ~clk;
end
endtask
task reset_gen;
begin
reset_a = 1'b1;
#50 reset_a = 1'b0;
end
endtask
task start_gen;
begin
start = 1'b1;
#50;
forever begin
start = 1'b1;
#50 start = 1'b0;
@(negedge done_flag);
#25;
end
end
endtask
task data_gen;
begin
dataa = 8'hff;
datab = 8'hff;
#50;
forever begin
@(negedge done_flag)
#25 dataa = dataa +24;
datab = datab + 51;
end
end
endtask
parameter IDLE = 0;
parameter LSB = 1;
parameter MID = 2;
parameter MSB = 3;
parameter CALC_DONE = 4;
parameter ERR = 5;
reg [9*9-1:0] cstate;
always@(mult8_u0.uMult8_ctrl_0.cst)begin
case(mult8_u0.uMult8_ctrl_0.cst)
IDLE : cstate = "IDLE ";
LSB : cstate = "LSB ";
MID : cstate = "MID ";
MSB : cstate = "MSB ";
CALC_DONE : cstate = "CALC_DONE";
ERR : cstate = "ERR ";
default : cstate = "UNKNOWN ";
endcase
end
endmodule
vlib work
vlog mult8.v tb_mult8.v mult4.v adder16.v mux4.v
vlog shifter.v seven_segment_ctrl.v reg16.v counter.v mult8_ctrl.v
vsim work.tb_mult8
view wave
add wave -divider System_Control_Signals
add wave -radix unsigned /clk
add wave -radix unsigned /reset_a
add wave -radix unsigned /start
add wave -divider Multiplicands
add wave -radix hex /dataa
add wave -radix hex /datab
add wave -divider mux4
add wave -radix unsigned -format literal /mult8_u0/uMux4_0/sel
add wave -radix hex /mult8_u0/uMux4_0/mux_out
add wave -radix unsigned -format literal /mult8_u0/uMux4_1/sel
add wave -radix hex /mult8_u0/uMux4_1/mux_out
add wave -divider Mult4
add wave -radix hex /mult8_u0/uMult4_0/product
add wave -radix unsigned /mult8_u0/uMult4_0/product
add wave -divider Shifter
add wave -radix unsigned /mult8_u0/uShifter_0/shift_ctrl
add wave -radix hex /mult8_u0/uShifter_0/shift_out
add wave -radix unsigned /mult8_u0/uShifter_0/shift_out
add wave -divider Adder
add wave -radix unsigned /mult8_u0/uAdder16_0/dataa
add wave -radix unsigned /mult8_u0/uAdder16_0/datab
add wave -radix unsigned /mult8_u0/uAdder16_0/sum
add wave -divider Reg16
add wave -radix unsigned /mult8_u0/uReg16_0/datain
add wave -radix unsigned -format literal /mult8_u0/uReg16_0/sclr_n
add wave -radix unsigned -format literal /mult8_u0/uReg16_0/clk_ena
add wave -radix unsigned /mult8_u0/uReg16_0/reg_out
add wave -divider Outputs
add wave -radix unsigned /done_flag
add wave -radix unsigned /product8x8_out
add wave -divider State
add wave -radix ASCII /cstate
run 5us
'Verilog Projects' 카테고리의 다른 글
Morse Code Generator. (0) | 2023.12.17 |
---|---|
Avalon Bus : GPIO (0) | 2023.11.12 |
Avalon Bus : PWM (0) | 2023.11.12 |
Avalon Bus Modeling. (1) | 2023.11.12 |
UART. (0) | 2023.11.08 |