본문 바로가기

Verilog Projects

8-Bit Multiplier.

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.

Simple Block Diagram
Mult8 Overall 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 신호로 연산의 시작과 끝을 제어한다. 

state table.
Block Diagram

 

State Diagram

 

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

 

RTL Viewer


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

 

 

 

Full Waveform

'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