ModelSim is awesome indeed!
I took the plunge and did the Altera tutorial that came with ModelSim. Look in the help-files of ModelSim and you'll find the tutorial.
Summary
I found a lot of ModelSim tutorials on the web, all for a different version of ModelSim. Then I decided to invest in reading/studying/doing the Altera-tutorial from the help-file of ModelSim. After one Sunday-afternoon I had the tutorial running. What a satisfaction!
I often write down all the steps I perform in a Word-document, my electronic diary. I simply use <Ctrl><Alt><PrtScr> and paste the screenshots in my Word-diary.
Because the bladeRF LMS-source is too difficult to simulate for the moment, I am a newby in ModelSim, I decided to design in VHDL a simple datasource for a sine with a DC-offset. Later I will test my DC-remover on this datasource.
I was too lazy to type in 32 12-bit values in the case-statement, so used a python-program to do this.
I managed to write and debug the code using ModelSim.
The whole struggle with ModelSim is in here but you might be wise and skip to the end for the final result.
I finally constructed the datasource.vhd and the testbench tdatasource.vhd
ModelSim
Tutorials on the web:
7. Mentor Graphics, 2008, Software
Version 6.4a, 88 pages
9. modelsim_tut.pdf from help-file
Modelsim 10.1d
Mentor Graphics Corporation, 2012, Version 10.1d, 80 pages
The last
one, number 9, is from the help-file of the current ModelSim on my laptop.
Which
version of ModelSim do I have?
ModelSim-Altera 10.1d (Quartus II
13.1)
ModelSim tutorial
I took the plunge and folowed the tutorial from the help-file in ModelSim, described above as #9.
It took me only one Sunday-afternoon and I had the counter-example running. The remaining evening was used to play with ModelSim. Awesome!
So, read the tutorial, take your time, and just try. This investment is worth your time!
Test-source for my
DC-remover
Fort
testing my DC-remover I need a simple source that I can simulate with ModelSim.
I want
to construct a simple source that delivers a sinus with an offset.
My
source has a 12-bit 2s-complement output. The average output will be 600.
12 bit
is 4096 max, so +/- 2048. Let’s make my sinus 600 + 1400*sin(wt), so the
outout-value will be 600-1400= -800 … 600+1400=2000.
The
output will be -800…2000.
If my
DC-remover is OK, the final output will be +/- 1400, so the original sine with
DC-offset removed.
Port
specification:
entity datasource is
port (
reset :
in std_logic;
clk : in std_logic;
sdata : out signed(11
downto 0)
) ;
end entity;
samplerate
is 4 MHz. I want 32 samples/period. So my sine has a frequency of 4/32 MHz =
125 kHz.
I need
an internal 5 bits counter. This counter is reset by the signal reset and
increments with every clk-pulse.
The
5-bits output of this counter selects a number from a table. Perhaps a case
statement.
The
code-fragment for the counter:
signal
index: std_logic_vector(4 downto 0);
process (clk, reset)
begin
if (reset='1') then
tmp <= "00000";
elsif (rising_edge(clk)) then
index <= index + 1;
end if;
end process;
And the
case=statement to calculate the 12-bit output:
signal tmpdata:
std_logic_vector(11 downto 0);
myproc: process (index)
begin
case(index) is
when “00000” => tmpdata <=
“000000000000”;
when “00001” => tmpdata <=
“000000111111”;
….
when “11110” => tmpdata <=
“111111100000”;
when “11111” => tmpdata <=
“111111111000”;
when others => tmpdata ,=
“000000000000”;
end case;
end process my_proc;
sdata <= tmpdata;
The
right values for the right-side of the when can be calculated with a simple
python-program
(and I
must admit I did not study the tobin-code, but it works (me coward!))
# GenVHDLsin01.py
# Apr-2014 Kees de Groot
#
# generate VHDL when
statements for sine-wave
import pylab as pl
import numpy as np
from math import sin,
cos, pi
n = 32
def tobin(x,
count=8):
"""
Integer to binary
Count is number of bits
"""
return "".join(map(lambda
y:str((x>>y)&1), range(count-1, -1, -1)))
for i in range(n):
data = sin(2 * pi * i / n)
output = 600 + 1400 * data
intout = int(output)
#print i, data, output, intout, bin(intout),
tobin(intout,12)
print "when", '"'+
tobin(i,5)+'"'," => tmpdata <= ", '"' +
tobin(intout,12) + '"'
which
outputs:
when
"00000" => tmpdata
<= "001001011000"
when
"00001" => tmpdata
<= "001101101001"
when
"00010" => tmpdata
<= "010001101111"
when
"00011" => tmpdata
<= "010101100001"
when
"00100" => tmpdata
<= "011000110101"
when
"00101" => tmpdata
<= "011011100100"
when
"00110" => tmpdata
<= "011101100101"
when
"00111" => tmpdata
<= "011110110101"
when
"01000" => tmpdata
<= "011111010000"
when
"01001" => tmpdata
<= "011110110101"
when
"01010" => tmpdata
<= "011101100101"
when
"01011" => tmpdata
<= "011011100100"
when
"01100" => tmpdata
<= "011000110101"
when
"01101" => tmpdata <= "010101100001"
when
"01110" => tmpdata
<= "010001101111"
when
"01111" => tmpdata
<= "001101101001"
when
"10000" => tmpdata
<= "001001011000"
when
"10001" => tmpdata
<= "000101000110"
when
"10010" => tmpdata
<= "000001000000"
when
"10011" => tmpdata
<= "111101001111"
when
"10100" => tmpdata
<= "111001111011"
when
"10101" => tmpdata
<= "110111001100"
when
"10110" => tmpdata
<= "110101001011"
when
"10111" => tmpdata
<= "110011111011"
when
"11000" => tmpdata
<= "110011100000"
when "11001" => tmpdata <= "110011111011"
when
"11010" => tmpdata
<= "110101001011"
when
"11011" => tmpdata
<= "110111001100"
when
"11100" => tmpdata
<= "111001111011"
when
"11101" => tmpdata
<= "111101001111"
when
"11110" => tmpdata
<= "000001000000"
when
"11111" => tmpdata
<= "000101000110"
So, the
case=statement to calculate the 12-bit output:
signal tmpdata:
std_logic_vector(11 downto 0);
myproc: process (index)
begin
case(index) is
when
"00000" => tmpdata
<= "001001011000"
when
"00001" => tmpdata
<= "001101101001"
when
"00010" => tmpdata
<= "010001101111"
when
"00011" => tmpdata
<= "010101100001"
when
"00100" => tmpdata
<= "011000110101"
when
"00101" => tmpdata
<= "011011100100"
when
"00110" => tmpdata
<= "011101100101"
when "00111" => tmpdata <= "011110110101"
when
"01000" => tmpdata
<= "011111010000"
when
"01001" => tmpdata
<= "011110110101"
when
"01010" => tmpdata
<= "011101100101"
when
"01011" => tmpdata
<= "011011100100"
when
"01100" => tmpdata
<= "011000110101"
when
"01101" => tmpdata
<= "010101100001"
when
"01110" => tmpdata
<= "010001101111"
when
"01111" => tmpdata
<= "001101101001"
when
"10000" => tmpdata
<= "001001011000"
when
"10001" => tmpdata
<= "000101000110"
when
"10010" => tmpdata
<= "000001000000"
when
"10011" => tmpdata
<= "111101001111"
when
"10100" => tmpdata
<= "111001111011"
when
"10101" => tmpdata
<= "110111001100"
when
"10110" => tmpdata
<= "110101001011"
when
"10111" => tmpdata
<= "110011111011"
when
"11000" => tmpdata
<= "110011100000"
when
"11001" => tmpdata
<= "110011111011"
when
"11010" => tmpdata
<= "110101001011"
when
"11011" => tmpdata
<= "110111001100"
when
"11100" => tmpdata
<= "111001111011"
when
"11101" => tmpdata
<= "111101001111"
when
"11110" => tmpdata
<= "000001000000"
when
"11111" => tmpdata
<= "000101000110"
when others => tmpdata <=
“000000000000”;
end case;
end process my_proc;
sdata <= tmpdata;
Now
collect all fragments and produce the VHDL-program datasource.vhd
Note that I forgot the semicolons, not too much editing adding 32 semicolons...
-- datasource.vhd
-- May-2014 Kees de
Groot
-- test-program for my DC-remover
-- this device outputs a 2s-complement sine of 32
points
entity datasource is
port (
reset : in std_logic;
clk : in std_logic;
sdata : out signed(11 downto 0)
) ;
end;
architecture mydatasource of datasource is
begin
signal index:
std_logic_vector(4 downto 0);
calcindex: process (clk, reset)
begin
if
(reset='1') then
tmp
<= "00000";
elsif
(rising_edge(clk)) then
index <= index + 1;
end
if;
end
process calcindex;
signal tmpdata: std_logic_vector(11 downto 0);
myproc:
process (index)
begin
case(index)
is
when "00000"
=> tmpdata <= "001001011000";
when "00001"
=> tmpdata <=
"001101101001";
when "00010"
=> tmpdata <=
"010001101111";
when "00011"
=> tmpdata <=
"010101100001";
when "00100"
=> tmpdata <=
"011000110101";
when "00101"
=> tmpdata <=
"011011100100";
when "00110"
=> tmpdata <=
"011101100101";
when "00111"
=> tmpdata <=
"011110110101";
when "01000"
=> tmpdata <=
"011111010000";
when "01001"
=> tmpdata <=
"011110110101";
when "01010"
=> tmpdata <=
"011101100101";
when "01011"
=> tmpdata <=
"011011100100";
when "01100"
=> tmpdata <=
"011000110101";
when "01101"
=> tmpdata <=
"010101100001";
when "01110"
=> tmpdata <=
"010001101111";
when "01111"
=> tmpdata <=
"001101101001";
when "10000"
=> tmpdata <=
"001001011000";
when "10001"
=> tmpdata <= "000101000110";
when "10010"
=> tmpdata <=
"000001000000";
when "10011"
=> tmpdata <=
"111101001111";
when "10100"
=> tmpdata <=
"111001111011";
when "10101"
=> tmpdata <=
"110111001100";
when "10110"
=> tmpdata <=
"110101001011";
when "10111"
=> tmpdata <=
"110011111011";
when "11000"
=> tmpdata <=
"110011100000";
when "11001"
=> tmpdata <=
"110011111011";
when "11010"
=> tmpdata <=
"110101001011";
when "11011"
=> tmpdata <=
"110111001100";
when "11100"
=> tmpdata <=
"111001111011";
when "11101"
=> tmpdata <=
"111101001111";
when "11110"
=> tmpdata <=
"000001000000";
when "11111"
=> tmpdata <=
"000101000110";
when
others => tmpdata <= “000000000000”;
end
case;
end
process my_proc;
sdata
<= tmpdata;
end mydatasource;
I need a
testbed, the VHDL-program tdatasource.vhd
-- tdatasource.vhd
-- May-2014 Kees de Groot
-- test-program for the datasource to test my
DC-remover
-- this device simply tests the datasource
entity test_datasource is
PORT (
sourceout : out signed(11 downto 0);
end;
architecture mytest of test_datasourece is
COMPONENT datasource
port (
reset : in std_logic;
clk : in std_logic;
sdata : out signed(11 downto 0)
) ;
END COMPONENT ;
SIGNAL clk :
bit := '0';
SIGNAL reset : bit := '0';
begin
dut : datasource
PORT MAP (
sdata => sdata,
clk =>
clk,
reset =>
reset );
clock : PROCESS
begin
wait for 10
ns; clk <= not clk;
end PROCESS clock;
stimulus : PROCESS
begin
wait for 5
ns; reset <= '1';
wait for 4
ns; reset <= '0';
wait;
end PROCESS stimulus;
end only;
I copy
these two files datasource.vhd and tdatasource.vhd to C:\altera\work
Then
start ModelSim, point to this directory, compile, start simulation and run
I start
NotePad, paste the above source in NotePad, then save it to
C:\altera\work\datasource.vhd
The same
for tdatasource.vhd
Now I
should have both files in C:\altera\work:
The
other files from the tutorial are still there but that does not harm hopefully…
Now
start ModelSim and point to that directory
Simply
close this screen
Oops, it
starts the last project,
So File
> New Project
click on
Add existing File
Browse
and add datasource and tdatasource
click
Create Simulation
Cancel
Simulate > start simulation
Cancel
I have
to compile first!
Compile
> compile all
#
Compile of tdatasource.vhd failed with 2 errors.
# 2
compiles, 2 failed with 6 errors.
Of
course, 1st time!
I did
not specify any library, I thought that was not necessary for a simulation: stupid!
doubleclick
on t\datasource.vhd in the project menu at the left opens the source in
WordPad.
I have
to add libraries: which? IEEE…??
Parenthesis missing
Correct
to
PORT (
sourceout : out signed(11 downto 0));
Save and
compile again
Same
error
I still
think it is a library problem
I’ll
have a look in the LMS-bladerf file and copy the IEE lib spec
Add
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
to the
start of both vhd-files
Save and
compile again
Typo
datasourece, should be datasource
Now I
see:
# 2
compiles, 2 failed with 42 errors.
#
Compile of datasource.vhd failed with 40 errors.
#
Compile of tdatasource.vhd failed with 2 errors.
# 2
compiles, 2 failed with 42 errors.
library ieee ;
use
ieee.std_logic_1164.all ;
use
ieee.numeric_std.all ;
-- tdatasource.vhd
-- May-2014 Kees de Groot
-- test-program for the datasource to test my
DC-remover
-- this device simply tests the datasource
entity test_datasource is
PORT ( sdata
: out signed(11 downto 0));
end;
architecture mytest of test_datasource is
COMPONENT datasource
port (
reset : in std_logic;
clk : in std_logic;
sdata : out signed(11 downto 0)
) ;
END COMPONENT ;
SIGNAL clk :
std_logic := '0';
SIGNAL reset : std_logic := '0';
begin
dut : datasource
PORT MAP (
sdata =>
sdata,
clk =>
clk,
reset =>
reset );
clock : PROCESS
begin
wait for 10
ns; clk <= not clk;
end PROCESS clock;
stimulus : PROCESS
begin
wait for 5
ns; reset <= '1';
wait for 4
ns; reset <= '0';
wait;
end PROCESS stimulus;
end mytest;
tdatasource.vhd
is now succesfull compiled!
Now
concentrate on datasource.vhd
Doubleclick
in the lower window on the red error-message opens a window with the
errormessages
Double
click on the file datasource.vhd to open it in the editor
After
some corrections the source compiles without errors:
library ieee ;
use
ieee.std_logic_1164.all ;
use
ieee.numeric_std.all ;
-- datasource.vhd
-- May-2014 Kees de
Groot
-- test-program for my DC-remover
-- this device outputs a 2s-complement sine of 32
points
entity datasource is
port (
reset : in std_logic;
clk : in std_logic;
sdata : out signed(11
downto 0)
) ;
end datasource;
architecture mydatasource of datasource is
signal
tmpdata: signed(11 downto 0);
begin
cal signal indexx: signed(4 downto 0);
cindex: process (clk, reset)
begin
if
(reset='1') then
tmpdata <= "000000000000";
elsif
(rising_edge(clk)) then
indexx <= indexx + 1;
end
if;
end
process calcindex;
myproc:
process (indexx)
begin
case(indexx)
is
when "00000"
=> tmpdata <=
"001001011000";
when "00001"
=> tmpdata <= "001101101001";
when "00010"
=> tmpdata <=
"010001101111";
when "00011"
=> tmpdata <=
"010101100001";
when "00100"
=> tmpdata <=
"011000110101";
when "00101"
=> tmpdata <=
"011011100100";
when "00110"
=> tmpdata <=
"011101100101";
when "00111"
=> tmpdata <=
"011110110101";
when "01000"
=> tmpdata <=
"011111010000";
when "01001"
=> tmpdata <=
"011110110101";
when "01010"
=> tmpdata <=
"011101100101";
when "01011"
=> tmpdata <=
"011011100100";
when "01100"
=> tmpdata <=
"011000110101";
when "01101"
=> tmpdata <=
"010101100001";
when "01110"
=> tmpdata <=
"010001101111";
when "01111"
=> tmpdata <=
"001101101001";
when "10000"
=> tmpdata <=
"001001011000";
when "10001"
=> tmpdata <=
"000101000110";
when "10010"
=> tmpdata <= "000001000000";
when "10011"
=> tmpdata <=
"111101001111";
when "10100"
=> tmpdata <=
"111001111011";
when "10101"
=> tmpdata <=
"110111001100";
when "10110"
=> tmpdata <=
"110101001011";
when "10111"
=> tmpdata <=
"110011111011";
when "11000"
=> tmpdata <=
"110011100000";
when "11001"
=> tmpdata <=
"110011111011";
when "11010"
=> tmpdata <=
"110101001011";
when "11011"
=> tmpdata <=
"110111001100";
when "11100"
=> tmpdata <=
"111001111011";
when "11101"
=> tmpdata <=
"111101001111";
when "11110"
=> tmpdata <=
"000001000000";
when "11111"
=> tmpdata <=
"000101000110";
when others => tmpdata <=
"000000000000";
end
case;
end
process myproc;
sdata
<= tmpdata;
end mydatasource;
Simulate
> start simulation
Quite
encouraging:
Right
click on the objects windows and “add wave”
Click on
run
Lower
left type “run 500 ns”
Well,
not any output still…
It looks
like indexx is never initialized, so remains at “XXXXX”
Change
if (reset='1') then
tmpdata <=
"000000000000";
index <= "00000";
elsif (rising_edge(clk)) then
end
simulation
save,
compile, simulate, run
It looks
like some signals are not defined yet!
I get
XXX in the wave-display.
Why?
Exactly what Brian explained: define signals in one process, at one place only.
No multiple assignments! If there more sources, one source tells "it is a ONE!" and another source yells "it is a ZERO" then what shouyld be the outcome??
I
changed my source and now it is ok. ModelSim is awesome indeed!!!
I tested
my datasource.vhd and now I can finally test my dcremover.vhd in the same way.
Here is
the final source of datasource.vhd
Note that I renamed index to indexx because index might be a reserved word perhaps?
library ieee ;
use
ieee.std_logic_1164.all ;
use
ieee.numeric_std.all ;
-- datasource.vhd
-- May-2014 Kees de
Groot
-- test-program for my DC-remover
-- this device outputs a 2s-complement sine of 32 points
entity datasource is
port (
reset : in std_logic;
clk : in std_logic;
sdata : out signed(11
downto 0)
) ;
end datasource;
architecture mydatasource of datasource is
signal indexx:
signed(4 downto 0);
signal
tmpdata: signed(11 downto 0);
begin
calcindex:
process (clk, reset)
begin
if
(reset='1') then
indexx <= "00000";
elsif
(rising_edge(clk)) then
indexx <= indexx + 1;
end
if;
end
process calcindex;
myproc:
process (indexx)
begin
case(indexx)
is
when "00000"
=> tmpdata <=
"001001011000";
when "00001"
=> tmpdata <=
"001101101001";
when "00010"
=> tmpdata <=
"010001101111";
when "00011"
=> tmpdata <=
"010101100001";
when "00100"
=> tmpdata <=
"011000110101";
when "00101"
=> tmpdata <=
"011011100100";
when "00110"
=> tmpdata <=
"011101100101";
when "00111"
=> tmpdata <=
"011110110101";
when "01000"
=> tmpdata <=
"011111010000";
when "01001"
=> tmpdata <=
"011110110101";
when "01010"
=> tmpdata <=
"011101100101";
when "01011"
=> tmpdata <=
"011011100100";
when "01100"
=> tmpdata <=
"011000110101";
when "01101"
=> tmpdata <=
"010101100001";
when "01110"
=> tmpdata <=
"010001101111";
when "01111"
=> tmpdata <=
"001101101001";
when "10000"
=> tmpdata <=
"001001011000";
when "10001"
=> tmpdata <=
"000101000110";
when "10010"
=> tmpdata <=
"000001000000";
when "10011"
=> tmpdata <=
"111101001111";
when "10100"
=> tmpdata <=
"111001111011";
when "10101"
=> tmpdata <= "110111001100";
when "10110"
=> tmpdata <=
"110101001011";
when "10111"
=> tmpdata <=
"110011111011";
when "11000"
=> tmpdata <=
"110011100000";
when "11001"
=> tmpdata <=
"110011111011";
when "11010"
=> tmpdata <=
"110101001011";
when "11011"
=> tmpdata <=
"110111001100";
when "11100"
=> tmpdata <=
"111001111011";
when "11101"
=> tmpdata <=
"111101001111";
when "11110"
=> tmpdata <=
"000001000000";
when "11111"
=> tmpdata <=
"000101000110";
when others => tmpdata <=
"000000000000";
end
case;
end
process myproc;
sdata
<= tmpdata;
end mydatasource;
Somehow I found this URL on the web:
Analogue Waveforms
Modelsim can display a signal in your VHDL/Verilog
design as an analogue signal. One use for this is when you want to visualise
the output of a digital to analogue converter to see if you have synthesised
the waveform as you intended. To do this you can right-click on the signal name
in the Wave window and select it's properties. Switch to the Format tab and
select 'Analogue'. You can optionally set a maximum value for the signal so
that Modelsim can stretch your waveform to fit the height of the row. For
example, set it to 255 for an 8-bit DAC value.
It is even possible to get a decimal value of the wave under the cursor!!
Epilogue
Yes, ModelSim is awesome indeed. Testbenches are not difficult to construct once you grasp the overall idea. Now I am gonna make a testbench for my DC-remover using the above datasource.
Don't be afraid/shy study Altera's tutorial!