系统Verilog Cordic正弦波发生器

时间:2019-12-04 18:43:16

标签: system-verilog cordic

对于一个大学项目,我必须参加一个小组,设计一个CORDIC正弦波发生器。我的小组将CORDIC分为多个部分,以使我们能够同时工作。现在,我已经将模块集成在一起(以计算单级的纯正弦和余弦值,例如旋转60度),而我的输出值不再是我所期望的。我相信我可能误解了有关CORDIC算法的一些基础知识,因此该程序带来了价值。这是我解决这个问题的最后努力。

我已经将到目前为止所拥有的代码与在ModelSim中用于测试的do文件一起附加了。

用于预先计算幅度计算器的下一个值的方向计算器

/*DirectionCalculator
 *Author:   -------------------
 *Description:  
    A calculator that finds out if the next angle is added 
    or subtracted based on if the current angle.
    If greater subtract if smaller add.  
 *Version:  V 2.2
 *Log:
    -Created input output
    -Conditionals for next tirection
    -Moved the lookup table from controller to direction calculator
     to reduce amout of data handled by controller
    -Removed signed portion of Angle_Table to increase accuracy and the signed 
     part will never be  used as the angle will alwasy be between 0 and 90
    -Shifted start value to 45 degrees as the calcualtor needs to be a step ahead

*Input Description
  -
*/

module DirectionCalculator(Start, Reset, TAngle, Done, N_Dir, Zout);
  input Start, Reset;
  input[15:0] TAngle;
  output logic Done, N_Dir;
  output logic [15:0] Zout;

  //Registers

  reg Res_flag = 0;
  reg [3:0] n;
  reg [15:0] Z, Angle_Table[0:14];

  //lookup table
  //Bits in table are decimal representative
  //Each bit represents a value of pi so that 10... is pie 01... is 1/2 pi in radians
  assign Angle_Table[0]  = 16'b0100000000000000; //fist angle of 45 = arctan(2^-0)
  assign Angle_Table[1]  = 16'b0010010111001000; //26.565 = arctan(2^-1)
  assign Angle_Table[2]  = 16'b0001001111110110; //14.036 = arctan(2^-2)
  assign Angle_Table[3]  = 16'b0000101000100010;
  assign Angle_Table[4]  = 16'b0000010100010110;
  assign Angle_Table[5]  = 16'b0000001010001100;
  assign Angle_Table[6]  = 16'b0000000101000110;
  assign Angle_Table[7]  = 16'b0000000010100011;
  assign Angle_Table[8]  = 16'b0000000001010001;
  assign Angle_Table[9]  = 16'b0000000000101001;
  assign Angle_Table[10] = 16'b0000000000010100;
  assign Angle_Table[11] = 16'b0000000000001010;
  assign Angle_Table[12] = 16'b0000000000000101;
  assign Angle_Table[13] = 16'b0000000000000011;
  assign Angle_Table[14] = 16'b0000000000000001;


  always @(posedge Start or posedge Reset) 
  begin 

  //Reset to Start values
    if(Reset && !Res_flag) begin
      Z = Angle_Table[0]; //Angle started at is 45 degrees
      n = 1;
      Res_flag = 0;//flag reset as complete
      Done = 0;
    end else if (Reset) //
      Res_flag = 0;

  //Check if the controller is asking to operate
    if (Start) begin
      if(n == 15) begin
        Zout <= Z;
      end else if(n < 15) begin
            Done = 0;
         //Calculate Direction
        if(Z < TAngle) begin //Angle less than desired
          Z <= Z + Angle_Table[n]; //Accumulate Total Angle
          N_Dir <= 1'b1; //Set Direction to Rotate anticlockwise
        end else if(Z > TAngle)begin //Angle Grater than desired
          Z <= Z - Angle_Table[n]; //Accumulate Total Angle
          N_Dir <= 1'b0; //Set direction to rotate Clockwise
        end 
        n++; //Itterate next step
        #5 Done = 1; //Tell the controller the task is complete
      end
    end
  end
  endmodule

用于计算X和Y值(分别为Cos / Sin)的振幅计算

/*Amplitude_Calculator.sv
 *Author: ------------
 *Description:  Used to calculate the amplitude of the Wave at a certain angle
                through the use of shifting.
 *
 */

// This part just design the calculation about sin and cos waveform generator.
// the calculation just like:
// Xi+1 = Xi-[Yi*di*2^(-1)]
// Yi+1 = Yi+[Xi*di*2^(-1)]                   

module AmplitudeCalculator(Dir, Start, Xin, Yin, AngleShift, Xout, Yout, Done);

input Dir, Start;// N_Dir means "di"
input signed [15:0] Xin, Yin;// there are 16 bits input, 
                                  // Xin is Xi, Yin is Yi and 
input signed [4:0] AngleShift;           // the AngleShift is 2^(-1)
output logic Done;                // that just means the calculation is finished
output logic signed [15:0] Xout, Yout;// there are 16 bits output,
                              // Xout is Xi+1
                              // Yout is Yi+1


  always @(posedge Start)// if the Start value is 1, run the calculation.
  begin

    Done = 1'd0; //set the done value to 0 to prevent premature finish

    #5

    Xtemp <= Xin >>> AngleShift;// X_temp is the value of Xin right shift,
                               // and X_temp will change because of AngleShift
    Ytemp <= Yin >>> AngleShift;// Y_temp is the value of Xin right shift,
                              // and X_temp will change because of AngleShift
    #5
    //Multiplexers Selecting corre                    
    Xout <= Dir ? Xin - Ytemp : Xin + Ytemp; //Multiplexes output for Xout selecting addition or subtraction
    Yout <= Dir ? Yin + Xtemp : Yin - Xtemp; //Multiplexex output for Yout selecting addition or subtraction

    #5

    Done = 1'b1; //inform the controller that the process is finished

  end

endmodule

在计算器之间迭代并传递值以防止模块重复的控制器

/* 
Controller
Author: -------------
Description: A module that acts as the controller for the other modules. 
It iterates values for the next sequence.
Version: 1.0

Inputs:
Yin
Xin
CLK = Clock signal
Yin_S = Yin Starting Value
Xin_S = Xin Starting Value
N_Dir = Next Direction
Done = This is an Input showing when both modules are done

Outputs:
Yout_F = Final Yout Output Value
Xout_F = Final Xout Output Value
AS = Angle Shift; amount of times we have to shift the angle
C_Dir = Current Direction
Yout
Xout
Start
*/


module Controller(Yin, Xin, CLK, Yin_S, Xin_S, Done, Yout_F, Xout_F, 
                  Yout, Xout, AS, C_Dir, N_Dir, Start, Reset);

  input Done, CLK, N_Dir;
  input signed [15:0] Yin_S, Xin_S, Yin, Xin;
  output logic Start, C_Dir, Reset;
  output logic signed [4:0] AS;
  output logic signed [15:0] Yout, Xout, Yout_F, Xout_F;

  reg signed [15:0] Yout_F_reg = 0;
  reg signed [15:0] Xout_F_reg = 0;
  reg signed [4:0] n = 0;
  reg CLK_flag = 0;
  enum{S0,S1,S2} cstate, nstate;

  //Assign Outputs to X Y registers
   assign Xout_F = Xout_F_reg;
   assign Yout_F = Yout_F_reg;

  //next state Block
  always_comb
  begin  
    case (cstate)

      S0: nstate = S1; //state 0 always goes to state 1
      S1: if(n >= 13) nstate = S2; else nstate = S1; // repeat state 14 times to find final value of ordic rotation
      S2: nstate = S2; //end state output is set and program is stalled waiting for reset

    endcase
  end

  //Current state action Block
  always @(*) //occures when any input values change eg. cstate
  begin
    case (cstate)

    //Reset values state
    S0:   begin
               #5 Start = 0;
               Reset = 1;
               n = 0;
               #5 Reset = 0;
               Xout <= Xin_S;
               Yout <= Yin_S;
               AS <= n;
               C_Dir = 1;
               #5 Start = 1;

          end

    //Core itteration State
    S1:   begin
            #5 Start = 0;
            //itterate step
            n++;
            //pass calculated values over to AC
            Xout = Xin;
            Yout = Yin;
            C_Dir = N_Dir;
            AS = n; //set shift angle
            #5 Start = 1;

          end

    //Endstate Outputs X Y  values
    S2:   begin
            #5 Start = 0;
            //output 
            Xout_F_reg = Xin;
            Yout_F_reg = Yin;
          end



    endcase
  end

  //Incremnet Block incremnets to the next state upon completion of calculations
  //Set cstate to S0 when clock is input reseting the State machine
    always @(posedge Done or posedge CLK)
    begin
      //reset on positive edge of clock (do not know how to do this any other way)
    if (CLK && !CLK_flag) begin //reset state machine
      cstate = S0;
      CLK_flag = 1; //flag that the resest has occured
    end else
    if(!CLK) begin
      CLK_flag = 0; //set the flag to 0 whe clock is 0
    end

    if(Done)//continue to next state
      cstate = nstate; //change current state to next state when the calculater have finished

    end


endmodule

三个模块的组合

/*CORDIC_Core.sv
 *Author: -------------
 *Description: Combination of all the logic elements of the main cordic part
 *
 *
 *
 */

module CORDIC_Core(Clk, Yin_S, Xin_S, TAngle, Yout_F, Xout_F, Zout);

   input Clk;
   input [15:0] Yin_S, Xin_S, TAngle;
   output [15:0] Yout_F, Xout_F, Zout;

   wire [15:0] Y[1:0], X[1:0];
   wire [4:0] AS;
   wire D0, D1, C_Dir, N_Dir, Start, Reset; 

   //And for Done values

   assign Done = D0 && D1; 

   //isntaciate Blocks and connect with wires
      Controller C0 (Y[0], X[0], Clk, Yin_S, Xin_S, Done, Yout_F, Xout_F, 
                  Y[1], X[1], AS, C_Dir, N_Dir, Start, Reset);
      DirectionCalculator DC0 (Start, Reset, TAngle, D1, N_Dir, Zout);
      AmplitudeCalculator AC0 (C_Dir, Start, X[1], Y[1], AS, X[0], Y[0], D0);

endmodule

做测试文件

#Test_CORDIC_Core.do

#Setup

force Clk 0 1,0 500 -r 1000
#Xin set to 0.607 to test without amplifier (pre multipling by 0.0607)
force Xin_S 16'b0001001101101101
force Yin_S 16'b0000000000000000


#Test1 for angle shift of 60 degrees
force TAngle 16'b0010101010101011
run 950

#Test2 for angle shift of 20 degrees
force TAngle 16'b0000111000111000
#run 1050

非常感谢您浏览我的作品

这是我运行x和y最终值的代码时得到的测试结果 The results where the binary values are 16 bit with a decimal point at 000.0000000000000 portion os Modelsim Waveform

我知道程序中存在多个错误,但是我想首先解决此价值问题。我正在修复其他错误

0 个答案:

没有答案