作业要求
在FPGA上设计一个DDS模块,在DE0 开发板上运行,在FPGA芯片内部合成出数字波形即可。不用输出模拟信号,本模块满足以下条件
- 使用板载晶振的50MHz时钟,合成以下频率的信号
- 1、500KHz 正弦波信号。 2、1MHz 正弦波信号。 3、3MHz 正弦波信号。
- 频率字字长32位,波表ROM尺寸为 10比特地址,1024个word
- 波形格式为2补码格式,12比特量化
- 每个CLK输出一个有效样点。
- 输入信号为频率字和频率字输入使能信号
- 使用板载的拨码开关(Switch)控制生成的波形信号的不同频率。
注意:波表ROM代码是用matlab或C打印生成的。不要手写
人工绘制的电路结构RTL设计图
Quartus扫描生成的电路RTL图
- 顶层RTL图
- DDS_CORE_ROM RTL图
SignalTap截图
- 500KHz输出正弦波的样值波形截图
- 1MKHz输出正弦波的样值波形截图
- 3MKHz输出正弦波的样值波形截图
设计代码
1. 生成波表ROM的MATLAB代码
function generate_DDS_rom()
clc;
close all;
disp('##########################################');
disp('# generate_DDS_rom() RUN');
disp('##########################################');
%%///
% set your rom config here
rom_word_len = 12; % rom data word length in bit
rom_addr_len = 10; % rom address word length in bit
rom_file_name = 'DDS_CORE_ROM.v'; % rom file name
rom_file_dir = './'; % rom file dir path
description = 'DDS CORE ROM FILE' % rom description
%%///
rom_vec_len = 2^rom_addr_len;
index = [0:rom_vec_len-1] .';
rom_data_vec_float = sin(2*pi*index/rom_vec_len);
figure; plot(rom_data_vec_float); % for debug
rom_data_vec_int = fix(rom_data_vec_float * (2^(rom_word_len-1) - 1));
figure; plot(rom_data_vec_int); % for debug
rom_cfg.rom_word_len = rom_word_len ;
rom_cfg.rom_file_name = rom_file_name ;
rom_cfg.rom_file_dir = rom_file_dir ;
rom_cfg.description = description ;
gen_rom_rtl(rom_cfg, rom_data_vec_int);
end % generate_DDS_rom()
% ///////////////////////////////////////////////////////////////////////////////
% gen_rom_rtl()
% generate synthesizable rom hdl code(need synthesizer support).
% ///////////////////////////////////////////////////////////////////////////////
% INPUT:
% data vector, must be integer value
% rom word len
% rom file dir string
% rom file name string
% OUTPUT:
% verilog format rom file, all data in 2's complement code format
function gen_rom_rtl(rom_cfg, data_vec);
rom_word_len = rom_cfg.rom_word_len ;
rom_file_name = rom_cfg.rom_file_name ;
rom_file_dir = rom_cfg.rom_file_dir ;
description = rom_cfg.description ;
data_vec_len = length(data_vec);
addr_word_len = ceil(log2(data_vec_len));
% check input be integer value
data_vec_fixed = fix(data_vec);
diff_sum = sum(data_vec == data_vec_fixed);
% all integer elements will cause the diff_sum be vector length
if(diff_sum < data_vec_len)
fprintf(1,'# ERROR, gen_rom_rtl(), input data_vec must be integer value\n');
return;
end
rom_file_dir_name = strcat(rom_file_dir, rom_file_name);
data_vec_fixed_2c = data_vec_fixed + (2^rom_word_len) .* (data_vec_fixed < 0);
romNum = 2^addr_word_len;
data_str_cell = cell(data_vec_len, 1);
for(idx = 1:data_vec_len)
data_str_cell{idx} = Dec2BinStr(data_vec_fixed_2c(idx), rom_word_len);
end % for(idx = 1:data_vec_len)
if(romNum > data_vec_len)
for(idx = data_vec_len+1:romNum)
data_str_cell{idx} = Dec2BinStr(0, rom_word_len);
end
end
fid_rom_file = fopen(rom_file_dir_name, 'w');
if(fid_rom_file == -1)
errMsg = strcat('ERROR, gen_rom_rtl(), create file',rom_file_dir_name, ',failed');
fprintf(1, '%s\n', errMsg);
return;
end
% rom data print
% get rom module name
rom_name = rom_file_name;
len_rom_file_name = length(rom_file_name);
if(rom_name(len_rom_file_name-1:len_rom_file_name) == '.v')
rom_name(len_rom_file_name-1:len_rom_file_name) = [];
else
fprintf(1,'#WARNINIG, gen_rom_rtl(), rom_file_name may error, check it!\n');
end
fprintf(fid_rom_file, ...
'// ************************************************************** //\n');
fprintf(fid_rom_file, ...
'// FILE : %s \n', rom_file_name);
fprintf(fid_rom_file, ...
'// DSCP : %s\n', description);
fprintf(fid_rom_file, ...
'// ABOUT : auto generated rom file by gen_rom_rtl.m\n');
fprintf(fid_rom_file, ...
'// DATE : %s \n', datestr(now));
fprintf(fid_rom_file, ...
'// ************************************************************** //\n');
% generate the crom module
fprintf(fid_rom_file, ...
'// module %s()\n', rom_name);
fprintf(fid_rom_file, ...
'module %s(\n', rom_name);
fprintf(fid_rom_file, ...
' CLK , // clock\n');
fprintf(fid_rom_file, ...
' RA , // read address\n');
fprintf(fid_rom_file, ...
' RD ); // read data\n');
fprintf(fid_rom_file, ...
'input CLK;\n');
fprintf(fid_rom_file, ...
'input [%-2d :0] RA;\n', addr_word_len-1);
fprintf(fid_rom_file, ...
'output [%-2d :0] RD;\n', rom_word_len-1);
fprintf(fid_rom_file, ...
'reg [%-2d :0] RD;\n', rom_word_len-1);
fprintf(fid_rom_file, ...
'always @ (posedge CLK)\n');
fprintf(fid_rom_file, ...
' case(RA)\n');
for addr = 0:1:data_vec_len-1
fprintf(fid_rom_file, ...
' %-2d''d %-6d:RD = #1 %-2d''b %s; ', ...
addr_word_len,addr, rom_word_len, data_str_cell{addr+1});
fprintf(fid_rom_file, ...
'// %6d 0x%s \n', ...
data_vec_fixed(addr+1), dec2hex(data_vec_fixed_2c(addr+1)));
end
fprintf(fid_rom_file, ...
' default : RD = #1 0;\n');
fprintf(fid_rom_file, ...
' endcase\n');
fprintf(fid_rom_file, ...
'endmodule \n');
fclose(fid_rom_file);
fprintf(1,'# File: %s written\n', rom_file_dir_name);
end % function gen_rom_rtl()
% ////////////////////////////////////////////////////////////////////
function str = Dec2BinStr(data, word_len)
str = '';
for(idx = word_len-1:-1:0)
bit_val = bitand(1, bitshift(data, -idx));
str = strcat(str, int2str(bit_val));
end
end % function Dec2BinStr()
2. 波表ROM代码
module DDS_CORE_ROM(
CLK , // clock
RA , // read address
RD ); // read data
input CLK;
input [9 :0] RA;
output [11 :0] RD;
reg [11 :0] RD;
always @ (posedge CLK)
case(RA)
10'd 0 :RD = #1 12'b 000000000000; // 0 0x0
10'd 1 :RD = #1 12'b 000000001100; // 12 0xC
10'd 2 :RD = #1 12'b 000000011001; // 25 0x19
10'd 3 :RD = #1 12'b 000000100101; // 37 0x25
10'd 4 :RD = #1 12'b 000000110010; // 50 0x32
10'd 5 :RD = #1 12'b 000000111110; // 62 0x3E
10'd 6 :RD = #1 12'b 000001001011; // 75 0x4B
10'd 7 :RD = #1 12'b 000001010111; // 87 0x57
10'd 8 :RD = #1 12'b 000001100100; // 100 0x64
10'd 9 :RD = #1 12'b 000001110000; // 112 0x70
10'd 10 :RD = #1 12'b 000001111101; // 125 0x7D
10'd 11 :RD = #1 12'b 000010001010; // 138 0x8A
10'd 12 :RD = #1 12'b 000010010110; // 150 0x96
10'd 13 :RD = #1 12'b 000010100011; // 163 0xA3
10'd 14 :RD = #1 12'b 000010101111; // 175 0xAF
10'd 15 :RD = #1 12'b 000010111100; // 188 0xBC
10'd 16 :RD = #1 12'b 000011001000; // 200 0xC8
10'd 17 :RD = #1 12'b 000011010101; // 213 0xD5
10'd 18 :RD = #1 12'b 000011100001; // 225 0xE1
10'd 19 :RD = #1 12'b 000011101110; // 238 0xEE
10'd 20 :RD = #1 12'b 000011111010; // 250 0xFA
10'd 21 :RD = #1 12'b 000100000111; // 263 0x107
10'd 22 :RD = #1 12'b 000100010011; // 275 0x113
10'd 23 :RD = #1 12'b 000100011111; // 287 0x11F
10'd 24 :RD = #1 12'b 000100101100; // 300 0x12C
10'd 25 :RD = #1 12'b 000100111000; // 312 0x138
10'd 26 :RD = #1 12'b 000101000101; // 325 0x145
10'd 27 :RD = #1 12'b 000101010001; // 337 0x151
10'd 28 :RD = #1 12'b 000101011101; // 349 0x15D
10'd 29 :RD = #1 12'b 000101101010; // 362 0x16A
10'd 30 :RD = #1 12'b 000101110110; // 374 0x176
10'd 31 :RD = #1 12'b 000110000011; // 387 0x183
10'd 32 :RD = #1 12'b 000110001111; // 399 0x18F
10'd 33 :RD = #1 12'b 000110011011; // 411 0x19B
10'd 34 :RD = #1 12'b 000110100111; // 423 0x1A7
10'd 35 :RD = #1 12'b 000110110100; // 436 0x1B4
10'd 36 :RD = #1 12'b 000111000000; // 448 0x1C0
10'd 37 :RD = #1 12'b 000111001100; // 460 0x1CC
10'd 38 :RD = #1 12'b 000111011000; // 472 0x1D8
10'd 39 :RD = #1 12'b 000111100101; // 485 0x1E5
10'd 40 :RD = #1 12'b 000111110001; // 497 0x1F1
10'd 41 :RD = #1 12'b 000111111101; // 509 0x1FD
10'd 42 :RD = #1 12'b 001000001001; // 521 0x209
10'd 43 :RD = #1 12'b 001000010101; // 533 0x215
10'd 44 :RD = #1 12'b 001000100001; // 545 0x221
10'd 45 :RD = #1 12'b 001000101110; // 558 0x22E
10'd 46 :RD = #1 12'b 001000111010; // 570 0x23A
10'd 47 :RD = #1 12'b 001001000110; // 582 0x246
10'd 48 :RD = #1 12'b 001001010010; // 594 0x252
10'd 49 :RD = #1 12'b 001001011110; // 606 0x25E
10'd 50 :RD = #1 12'b 001001101010; // 618 0x26A
10'd 51 :RD = #1 12'b 001001110110; // 630 0x276
10'd 52 :RD = #1 12'b 001010000010; // 642 0x282
10'd 53 :RD = #1 12'b 001010001110; // 654 0x28E
10'd 54 :RD = #1 12'b 001010011001; // 665 0x299
10'd 55 :RD = #1 12'b 001010100101; // 677 0x2A5
10'd 56 :RD = #1 12'b 001010110001; // 689 0x2B1
10'd 57 :RD = #1 12'b 001010111101; // 701 0x2BD
10'd 58 :RD = #1 12'b 001011001001; // 713 0x2C9
10'd 59 :RD = #1 12'b 001011010100; // 724 0x2D4
10'd 60 :RD = #1 12'b 001011100000; // 736 0x2E0
10'd 61 :RD = #1 12'b 001011101100; // 748 0x2EC
10'd 62 :RD = #1 12'b 001011111000; // 760 0x2F8
10'd 63 :RD = #1 12'b 001100000011; // 771 0x303
10'd 64 :RD = #1 12'b 001100001111; // 783 0x30F
10'd 65 :RD = #1 12'b 001100011010; // 794 0x31A
10'd 66 :RD = #1 12'b 001100100110; // 806 0x326
10'd 67 :RD = #1 12'b 001100110010; // 818 0x332
10'd 68 :RD = #1 12'b 001100111101; // 829 0x33D
10'd 69 :RD = #1 12'b 001101001000; // 840 0x348
10'd 70 :RD = #1 12'b 001101010100; // 852 0x354
10'd 71 :RD = #1 12'b 001101011111; // 863 0x35F
10'd 72 :RD = #1 12'b 001101101011; // 875 0x36B
10'd 73 :RD = #1 12'b 001101110110; // 886 0x376
10'd 74 :RD = #1 12'b 001110000001; // 897 0x381
10'd 75 :RD = #1 12'b 001110001101; // 909 0x38D
10'd 76 :RD = #1 12'b 001110011000; // 920 0x398
10'd 77 :RD = #1 12'b 001110100011; // 931 0x3A3
10'd 78 :RD = #1 12'b 001110101110; // 942 0x3AE
10'd 79 :RD = #1 12'b 001110111001; // 953 0x3B9
10'd 80 :RD = #1 12'b 001111000100; // 964 0x3C4
10'd 81 :RD = #1 12'b 001111010000; // 976 0x3D0
10'd 82 :RD = #1 12'b 001111011011; // 987 0x3DB
10'd 83 :RD = #1 12'b 001111100110; // 998 0x3E6
10'd 84 :RD = #1 12'b 001111110000; // 1008 0x3F0
10'd 85 :RD = #1 12'b 001111111011; // 1019 0x3FB
10'd 86 :RD = #1 12'b 010000000110; // 1030 0x406
10'd 87 :RD = #1 12'b 010000010001; // 1041 0x411
10'd 88 :RD = #1 12'b 010000011100; // 1052 0x41C
10'd 89 :RD = #1 12'b 010000100111; // 1063 0x427
10'd 90 :RD = #1 12'b 010000110001; // 1073 0x431
10'd 91 :RD = #1 12'b 010000111100; // 1084 0x43C
10'd 92 :RD = #1 12'b 010001000111; // 1095 0x447
10'd 93 :RD = #1 12'b 010001010001; // 1105 0x451
10'd 94 :RD = #1 12'b 010001011100; // 1116 0x45C
10'd 95 :RD = #1 12'b 010001100110; // 1126 0x466
10'd 96 :RD = #1 12'b 010001110001; // 1137 0x471
10'd 97 :RD = #1 12'b 010001111011; // 1147 0x47B
10'd 98 :RD = #1 12'b 010010000110; // 1158 0x486
10'd 99 :RD = #1 12'b 010010010000; // 1168 0x490
10'd 100 :RD = #1 12'b 010010011010; // 1178 0x49A
10'd 101 :RD = #1 12'b 010010100100; // 1188 0x4A4
10'd 102 :RD = #1 12'b 010010101111; // 1199 0x4AF
10'd 103 :RD = #1 12'b 010010111001; // 1209 0x4B9
10'd 104 :RD = #1 12'b 010011000011; // 1219 0x4C3
10'd 105 :RD = #1 12'b 010011001101; // 1229 0x4CD
10'd 106 :RD = #1 12'b 010011010111; // 1239 0x4D7
10'd 107 :RD = #1 12'b 010011100001; // 1249 0x4E1
10'd 108 :RD = #1 12'b 010011101011; // 1259 0x4EB
10'd 109 :RD = #1 12'b 010011110101; // 1269 0x4F5
10'd 110 :RD = #1 12'b 010011111111; // 1279 0x4FF
10'd 111 :RD = #1 12'b 010100001000; // 1288 0x508
10'd 112 :RD = #1 12'b 010100010010; // 1298 0x512
10'd 113 :RD = #1 12'b 010100011100; // 1308 0x51C
10'd 114 :RD = #1 12'b 010100100101; // 1317 0x525
10'd 115 :RD = #1 12'b 010100101111; // 1327 0x52F
10'd 116 :RD = #1 12'b 010100111001; // 1337 0x539
10'd 117 :RD = #1 12'b 010101000010; // 1346 0x542
10'd 118 :RD = #1 12'b 010101001011; // 1355 0x54B
10'd 119 :RD = #1 12'b 010101010101; // 1365 0x555
10'd 120 :RD = #1 12'b 010101011110; // 1374 0x55E
10'd 121 :RD = #1 12'b 010101100111; // 1383 0x567
10'd 122 :RD = #1 12'b 010101110001; // 1393 0x571
10'd 123 :RD = #1 12'b 010101111010; // 1402 0x57A
10'd 124 :RD = #1 12'b 010110000011; // 1411 0x583
10'd 125 :RD = #1 12'b 010110001100; // 1420 0x58C
10'd 126 :RD = #1 12'b 010110010101; // 1429 0x595
10'd 127 :RD = #1 12'b 010110011110; // 1438 0x59E
10'd 128 :RD = #1 12'b 010110100111; // 1447 0x5A7
10'd 129 :RD = #1 12'b 010110110000; // 1456 0x5B0
10'd 130 :RD = #1 12'b 010110111001; // 1465 0x5B9
10'd 131 :RD = #1 12'b 010111000001; // 1473 0x5C1
10'd 132 :RD = #1 12'b 010111001010; // 1482 0x5CA
10'd 133 :RD = #1 12'b 010111010011; // 1491 0x5D3
10'd 134 :RD = #1 12'b 010111011011; // 1499 0x5DB
10'd 135 :RD = #1 12'b 010111100100; // 1508 0x5E4
10'd 136 :RD = #1 12'b 010111101100; // 1516 0x5EC
10'd 137 :RD = #1 12'b 010111110101; // 1525 0x5F5
10'd 138 :RD = #1 12'b 010111111101; // 1533 0x5FD
10'd 139 :RD = #1 12'b 011000000101; // 1541 0x605
10'd 140 :RD = #1 12'b 011000001110; // 1550 0x60E
10'd 141 :RD = #1 12'b 011000010110; // 1558 0x616
10'd 142 :RD = #1 12'b 011000011110; // 1566 0x61E
10'd 143 :RD = #1 12'b 011000100110; // 1574 0x626
10'd 144 :RD = #1 12'b 011000101110; // 1582 0x62E
10'd 145 :RD = #1 12'b 011000110110; // 1590 0x636
10'd 146 :RD = #1 12'b 011000111110; // 1598 0x63E
10'd 147 :RD = #1 12'b 011001000101; // 1605 0x645
10'd 148 :RD = #1 12'b 011001001101; // 1613 0x64D
10'd 149 :RD = #1 12'b 011001010101; // 1621 0x655
10'd 150 :RD = #1 12'b 011001011101; // 1629 0x65D
10'd 151 :RD = #1 12'b 011001100100; // 1636 0x664
10'd 152 :RD = #1 12'b 011001101100; // 1644 0x66C
10'd 153 :RD = #1 12'b 011001110011; // 1651 0x673
10'd 154 :RD = #1 12'b 011001111011; // 1659 0x67B
10'd 155 :RD = #1 12'b 011010000010; // 1666 0x682
10'd 156 :RD = #1 12'b 011010001001; // 1673 0x689
10</