I am currently in the middle of a project where I am attempting to design a single cycle cpu. I am doing this without any pipe-lining, since that would greatly add to the complexity of the design. I am simply taking baby steps as I learn this. I find myself stuck at this portion where I am simply attempting to code a Program Counter(PC) using previously made components.
The model of my design looks like this picture here. Sorry, no idea why it came out dark, but if you click on it it shows correctly. The PC and theMUX are both 32 bit components, so I assume the adder is as well.
Here is the code I have been given, my implementation begins at the begin statement on line 41.
Pay no attention to it for now, its just a bunch of random gibberish I was attempting.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------
entity pc_update is
port( clk: in std_logic; -- clock
incH_ldL: in std_logic; -- increment PC = PC + 4 when high,
-- load PCInput when low
PCInput: in std_logic_vector(31 downto 0); -- external input for PC
InstrAddr: out std_logic_vector(31 downto 0) ); -- instruction address
end entity pc_update;
----------------------------------------------------
architecture pc_update_arch of pc_update is
component register32 is
port( clr: in std_logic; -- async. clear
clk: in std_logic; -- clock
ld: in std_logic; -- load
D: in std_logic_vector(31 downto 0); -- data input
Q: out std_logic_vector(31 downto 0) ); -- data output
end component register32;
component mux2to1_32 is
port( sel: in std_logic; -- selection bit input
X0: in std_logic_vector(31 downto 0); -- first input
X1: in std_logic_vector(31 downto 0); -- second input
Y: out std_logic_vector(31 downto 0)); -- output
end component mux2to1_32;
signal PC_current: std_logic_vector(31 downto 0); -- the current state of PC reg
signal PC_add_4: std_logic_vector(31 downto 0); -- output from the adder
signal PC_next: std_logic_vector(31 downto 0); -- output from the MUX
begin
PC: register32 Port Map(
clk, Q, clr, D);
MUX: mux2to1_32 Port Map(
X0,sel,X1,Y);
process (incH_ldL)
begin
wait until (clk = '1');
if incH_1dL = '0' then
InstrAddr <= X0;
else InstrAddr <= X1;
end if;
end process;
end architecture pc_update_arch;
I am fairly new to this so I have only a faint idea of how signals work, and no idea how I am supposed to implement the components into the design. I am also confused that I wasnt asked to build the adder ahead of time. Is it now necessary to use it as a component im guessing?
Anyhow, I have attempted different things that stumbled upon searching, such as the port mapping you see. But I always get some sort of error, currently the error im receiving is that objects Q, clr, and D are used but not declared. How do I declare them?
If I get rid of those statements, the error simply repeats for objects X0, X1, and Y.
Any help in the right direction would be greatly appreciated. Thanks guys!
Also, just in case you need them,
The register
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------
entity register32 is port(
clr: in std_logic; -- async. clear
clk: in std_logic; -- clock
ld: in std_logic; -- load
D: in std_logic_vector(31 downto 0); -- data input
Q: out std_logic_vector(31 downto 0) ); -- data output
end entity register32;
----------------------------------------------------
architecture register32_arch of register32 is
begin
process(clk, clr)
begin
if clr = '1' then
q <= x"00000000";
elsif rising_edge(clk) then
if ld = '1' then
q <= d;
end if;
end if;
end process;
END register32_arch;
and the MUX
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------
entity mux2to1_32 is
port( sel: in std_logic; -- selection bit input
X0: in std_logic_vector(31 downto 0); -- first input
X1: in std_logic_vector(31 downto 0); -- second input
Y: out std_logic_vector(31 downto 0)); -- output
end entity mux2to1_32;
----------------------------------------------------
architecture mux2to1_32_arch of mux2to1_32 is
begin
Y <= X1 when (SEL = '1') else X0;
end architecture mux2to1_32_arch;
EDIT
Ok, NO idea if I did this correctly, but I rewrote the portmaps. I was having errors of port names (sel, clk, X0, X1..etc) being "used but not initialized. So that is why clr, clk and ld have initial values. Once again, no idea if that is correct, but it made the errors go away. I also realized I never added the register32 and mux2to1_32 VHDL files to my project, and after doing so got rid of the other errors I was having.
So as stands, the code compiles, I have included in the project a VWF simulation file for testing, but I KNOW the results are gonna be incorrect.
I dont know everything that is wrong yet, but I know I need to do something with PC_add_4. THis value needs to basically be (PC_current + 4), but Im not sure how to do this.
Here is the updated portion of code(everything else is the same)
PC: register32 Port Map(
clr => '0',
clk => '0',
ld => '1',
Q => PC_current,
D => PC_next
);
MUX: mux2to1_32 Port Map(
sel => incH_ldL,
X0 => PCInput ,
X1 => PC_add_4,
Y => PC_next
);
process (incH_ldL)
begin
if (rising_edge(clk)) then
if incH_ldL = '0' then
InstrAddr <= PC_current;
else InstrAddr <= PC_add_4;
end if;
end if;
end process;
And, in case they help, my list of errors..im guessing the pin related errors are because I dont have any hardware assignments made yet.
Warning (10541): VHDL Signal Declaration warning at pc_update.vhd(38): used implicit default value for signal "PC_add_4" because signal was never assigned a value or an explicit default value. Use of implicit default value may introduce unintended design optimizations.
Warning (10492): VHDL Process Statement warning at pc_update.vhd(61): signal "clk" is read inside the Process Statement but isn't in the Process Statement's sensitivity list
Warning: Output pins are stuck at VCC or GND
Warning: Design contains 34 input pin(s) that do not drive logic
Warning: Found 32 output pins without output pin load capacitance assignment
Warning: The Reserve All Unused Pins setting has not been specified, and will default to 'As output driving ground'.
Warning: Can't generate programming files because you are currently using the Quartus II software in Evaluation Mode
Warning: No paths found for timing analysis
Critical Warning: No exact pin location assignment(s) for 66 pins of 66 total pins
SECOND EDIT
So yeah I fixed up my code by adding
PC_add_4 <= (PC_current + 4 );
after the port mappings, and adding "clk" to the process sensitivity list.
However my waveforms in my simulation are still wrong I believe, as shown here.
It appears to be treating incH_lDL as a clear signal, rather than simply passing PCInput to InstrAddr. This is most likely due to my setting of it to a default '0' in the port map. I did this earlier because it was giving me "used but not declared" errors. Ill try messing with it and post my findings.
Third EDIT
I have edited my code as such:
process (incH_ldL, clk)
begin
if rising_edge(clk) then
if (incH_ldL = '0') then
InstrAddr <= PCInput ;
else InstrAddr <= PC_add_4;
end if;
end if;
end process;
My simulation now shows that when incH_lDL = 0, PCInput is loaded into InstrAddr, however, when incH_lDL = 1, it simply loads the value '4', and doesnt increment at the start of every clock cycle like its supposed to...I need to make use of PC_current, but I am not sure how....sicne you cant assign one signal to another like "PC_current <= PCInput". I will try some more things,in the mean time, any pointers would be greatly appreciated.
FOURTH EDIT
THanks to anyone still reading this, and bearing through all the reading.
I have attempted to use PC_next and PC_current in my implementation, but have run into "multiple constant drivers for net "PC_next" errors.
MY process code:
process (incH_ldL, clk, PC_next, PC_current)
begin
if rising_edge(clk) then
if (incH_ldL = '0') then
PC_next <= PCInput;
else PC_next <= PC_add_4;
end if;
end if;
InstrAddr <= PC_current;
end process;
I am aware that this error comes when these assignments are made within loops? I am truly at a loss here at what to try next.
Your port maps in the first code need to be ported to signals. You are placing the port names of the components in the port map, which is incorrect. What you would like to do is create signals that can connect those components, and place them in the port map fields instead (to match the connections in your image).
Related
I'm using a CMOD A7 (Artix 7) and I need to trigger a process based on a pulse of around 10ns duration (blue line):
Normally I'd do triggering like this by having a process constantly compare the current value of the input line with the last value using a temporary register to hold the last value. However, I believe the oscillator on this board has a period of around 83ns which is far too slow for this approach.
If I was using pure digital electronics, this would be easy, connect a flipflop to the trigger, poll the output of that flipflop (which would change and latch with the input) and then reset it once I've read it and started my actions. So I would imagine there's a way to do this in VHDL but I'm led to believe using if rising_edge() on non-clock signals is a no-go.
Where do I start with this?
So the solution here is twofold:
Firstly, I can derive a 100MHz clock using the onboard MCCM and Vivado's ClockWiz IP.
I can also use the FDCE component provided by Vivado to utilise one of the onboard flipflops to extend the pulses and reset it after passing it through a few flipflops for synchronisation.
I've not tested this yet but I believe it should work:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library unisim;
use unisim.vcomponents.all;
entity input_syncroniser is
generic
(
in_pipe_len: in positive := 5
);
port
(
clk : in STD_LOGIC;
rst : in STD_LOGIC;
din : in STD_LOGIC;
dfo : out STD_LOGIC
);
end input_syncroniser;
architecture behavioural of input_syncroniser is
signal delayed_pulse: std_logic := '0';
signal in_pipe: std_logic_vector(in_pipe_len - 1 downto 0) := (others => '0');
signal pipe_head: std_logic := '0';
begin
FDCE_inst : FDCE
generic map
(
INIT => '0'
)
port map
(
Q => delayed_pulse,
C => din,
CE => '1',
CLR => pipe_head,
D => '1'
);
input_synchroniser: process(clk)
begin
if (rising_edge(clk)) then
in_pipe <= in_pipe(in_pipe'high downto in_pipe'low) & delayed_pulse;
end if;
end process;
pipe_head <= in_pipe(in_pipe'high);
dfo <= pipe_head;
end behavioural;
Warning: this is going to be long. Sorry if it's too verbose.
I'm just starting out on learning FPGAs and VHDL using Quartus Prime. Over the past few days I've taught myself:
How to write VHDL
How to make a component
How to write a testbench
How to use previously created and tested components - knitted together - to create a new component
What I can't work out though is how I would create a testbench that tests a new component that uses two existing components, when some of the signals that are in this new component are only internal signals.
So, here are two super-simple components that I have successfully written and tested with test benches. I realise this is not real world by the way, I'm just trying to take baby steps.
1. A four bit register
library ieee;
use ieee.std_logic_1164.all;
entity four_bit_reg is
port
(
bcd_in: in std_logic_vector(3 downto 0);
clk: in std_logic;
clr: in std_logic;
bcd_out: out std_logic_vector(3 downto 0)
);
end four_bit_reg;
architecture behaviour of four_bit_reg is
begin
process (clk,clr)
begin
if (clr = '1') then
bcd_out <= "0000";
elsif rising_edge(clk) then
bcd_out <= bcd_in;
end if;
end process;
end behaviour;
2. A BCD to seven segment converter
library ieee;
use ieee.std_logic_1164.all;
entity sev_seg is
port
(
bcd_value : in std_logic_vector(3 downto 0);
sev_seg_value : out std_logic_vector(6 downto 0)
);
end sev_seg;
architecture behaviour of sev_seg is
begin
sev_seg_process : process (bcd_value)
begin
case bcd_value is
when "0000" => sev_seg_value <="0111111"; -- 0
when "0001" => sev_seg_value <="0000110"; -- 1
when "0010" => sev_seg_value <="0111011"; -- 2
when "0011" => sev_seg_value <="1001111"; -- 3
when "0100" => sev_seg_value <="1100110"; -- 4
when "0101" => sev_seg_value <="1101101"; -- 5
when "0110" => sev_seg_value <="1111101"; -- 6
when "0111" => sev_seg_value <="0000111"; -- 7
when "1000" => sev_seg_value <="1111111"; -- 8
when "1001" => sev_seg_value <="1101111"; -- 9
when others => sev_seg_value <= "0000000"; -- A to F should show blank
end case;
end process sev_seg_process;
end behaviour;
First question: What do you call the two things above? Components? Modules? Entities? Something else?
I then use these two in another new component/entity/module (as applicable) as below:
library ieee;
use ieee.std_logic_1164.all;
entity two_modules is
port
(
bcd_pins : in std_logic_vector(3 downto 0);
sev_seg_pins : out std_logic_vector(6 downto 0)
);
end two_modules;
architecture behaviour of two_modules is
-- Internal signals
signal int_clk: std_logic;
signal int_bus: std_logic_vector(3 downto 0);
-- List any components used in the design
component four_bit_reg is
port
(
bcd_in: in std_logic_vector(3 downto 0);
clk: in std_logic;
clr: in std_logic;
bcd_out: out std_logic_vector(3 downto 0)
);
end component;
component sev_seg is
port
(
bcd_value : in std_logic_vector(3 downto 0);
sev_seg_value : out std_logic_vector(6 downto 0)
);
end component;
begin -- start the instances
fbr: four_bit_reg port map
(
clk => int_clk,
bcd_in => bcd_pins,
clr => '0',
bcd_out => int_bus
);
sseg: sev_seg port map
(
bcd_value => int_bus,
sev_seg_value => sev_seg_pins
);
end behaviour;
So, for this thing I have called two_modules, the framework for the test bench created by Quartus is as follows:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY two_modules_vhd_tst IS
END two_modules_vhd_tst;
ARCHITECTURE two_modules_arch OF two_modules_vhd_tst IS
-- constants
-- signals
SIGNAL bcd_pins : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL sev_seg_pins : STD_LOGIC_VECTOR(6 DOWNTO 0);
signal internal_clock : std_logic := '0';
COMPONENT two_modules
PORT (
bcd_pins : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
sev_seg_pins : OUT STD_LOGIC_VECTOR(6 DOWNTO 0)
);
END COMPONENT;
BEGIN
i1 : two_modules
PORT MAP (
-- list connections between master ports and signals
bcd_pins => bcd_pins,
sev_seg_pins => sev_seg_pins
);
internal_clock <= not internal_clock after 500 us;
init : PROCESS
-- variable declarations
BEGIN
-- code that executes only once
WAIT;
END PROCESS init;
always : PROCESS
-- optional sensitivity list
-- ( )
-- variable declarations
BEGIN
-- code executes for every event on sensitivity list
WAIT;
END PROCESS always;
END two_modules_arch;
As you can see I have created an internal clock and I would like to, purely for the purposes of learning how to do this type of thing, I stress I realise this is not a complete design, join the internal_clock (that I can see works and is a waveform in the waveform editor of Model Sim) to clk in the four_bit_reg.
I think and hope once I know how to do this I'll be able to plough on and get a real world, more complicated test bench knocked up. However, after much Googling I can find no reference on how to bind together signals from subcomponents. This may be because I am using completely the wrong terminology and there may be a perfect tutorial somewhere out there.
So:
How can I just for a start get my internal_clock connected to subcomponent, four_bit_reg's clk input?
What is the correct teminology for when you use and knit together things like four_bit_reg and sev_seg? Subcomponents? Something else?
Many thanks if you got this far!
With the comments, I understand that you are using an internal oscillator from Altera in your CPLD.
I suggest to add a third module named "internal_oscillator" which can be described as follow :
library ieee;
use ieee.std_logic_1164.all;
entity internal_oscillator is
port (
CLK : out std_logic
);
end entity;
architecture for_simulation_only of internal_oscillator is
constant C_HALF_PERIOD : time := 5 ns; -- 100MHz
signal clk_internal : std_logic := '0';
begin
clk_internal <= not clk_internal after C_HALF_PERIOD;
CLK <= clk_internal;
end architecture;
You can now add this module in your design and you'll get a clock without adding a new pin on your top level entity :
osc_inst : entity work.internal_oscillator
port map (CLK => int_clk);
In your two_models entity, add a new port for the clock signal:
entity two_modules is
port
(
clk : in std_logic;
bcd_pins : in std_logic_vector(3 downto 0);
sev_seg_pins : out std_logic_vector(6 downto 0)
);
end two_modules;
Remove the int_clk signal in the two_models architecture. Replace it with the previously defined input signal instead when you are connecting the submodules:
fbr: four_bit_reg port map
(
clk => clk_in,
bcd_in => bcd_pins,
clr => '0',
bcd_out => int_bus
);
In your testbench, connect the internal clock signal internal_clock into that port of the two_modules:
PORT MAP (
-- list connections between master ports and signals
clk_in => internal_clock,
bcd_pins => bcd_pins,
sev_seg_pins => sev_seg_pins
);
In most cases the clock is an input to the module. Often accompanied by a reset.
If you look around on the www for example VHDL code you will notice that every module, has a clock input.
There are general two exceptions:
Test-benches generate an artificial clock inside to drive the Device Under test.
Modules which simulate a real clock generating circuit e.g. a Crystal oscillator.
I have this problem with the VHDL synthesis. I read in multiple articles that the "wait" statement is synthesizable if I only use one "wait until"/process, so that's what I did. So I tried to make a counter which shows at what floor I am (my project consists of an elevator in Logic Design), and it should open the doors for 5 seconds at floors which were ordered. The problem is with the wait statement. I don't know what to replace it to make it work in ISE too.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity counter is
port(clk1: in std_logic;
enable2:in std_logic;
input_mux: in std_logic;
dir: in std_logic;
reset,s_g,s_u: in std_logic;
q_open: out std_logic;
q: out std_logic_vector(3 downto 0));
end counter;
architecture c1 of counter is
signal flag: std_logic:='0';
component test
port(clock: in std_logic;
a: in std_logic_vector(3 downto 0);
notify: out std_logic);
end component;
begin
delay: test port map(clk1,"0101",flag);
process
variable temp:std_logic_vector(3 downto 0):="0000";
variable q_open_var:std_logic:='0';
begin
if (enable2='1') then
if (s_g='1' and s_u='1') then
if (RESET='1') then
temp:="0000";
elsif (CLK1'EVENT and CLK1='1') then
if (DIR='1') then
temp:=temp+1;
elsif(DIR='0') then
temp:=temp-1;
end if;
end if;
end if;
end if;
if (input_mux='1') then
q_open_var:='1';
q_open<=q_open_var;
wait until (flag'event and flag='1');
q_open_var:='0';
end if;
q<=temp;
q_open<=q_open_var;
wait on clk1, reset;
end process;
end c1;
Although this structure is supported, you pushed over the limit of what is supported. The synthesis tool must generate registers from what you code. A register does have a clock and a reset input, but the synthesis tool does not know the words clk1 and reset. I.e. is you write
wait on clk1, reset;
The tool will not know what the reset is, nor what the clock is. Actually, both signals are considered clock triggers.
But you design is more problematic, as you have if-statements before the asynchronous reset and clock trigger. Although clock-gating is supported, you probably did not intend it.
Then there is a /second/ clock trigger in you statement: wait until (flag'event and flag='1');. I don't know what you are doing there, but how would you imagine this being realized in hardware?
You should really stick to standard/advised coding style for predictable behavior. I.e.
library ieee;
use ieee.numeric_std.all;
[...]
signal temp : unsigned(3 downto 0) := (others => '0');
begin
temp_proc: process(clk1, reset)
variable q_open_var : std_logic := '0';
begin
if rising_edge(clk1) then
if enable2='1' and s_g='1' and s_u='1' then
if dir = '1' then
temp <= temp + 1;
elsif dir = '0' then
temp <= temp - 1;
end if;
end if;
end if;
if reset = '1' then
temp <= (others => '0');
end if;
end process;
q <= std_logic_vector(temp);
(I left out the q_open part, as it is unclear what you want. Make a SEPARATE process for that, as it is not dependent on reset)
p.s. I like the five lines of end if; the most ;) Please use proper indenting next time. And use 'elsif' not 'else if'.
I need to generate a constant high signal pulse_out to output to an oscilloscope.
I tried letting the output signal pulse_out <='1' and this didnt work either. I believe due to my knowledge that an output port signal needs to be driven by a clock.
I also tried using combinational logic and letting a two signals that were opposite of each other make a new signal by using AND,OR and this did not work either.
I know it is a stupid question, but I am stumped.
Any sample code of showing how to output a constant high value of '1' would be great.
I agree with Josh's comment on checking your pin numbers and pin report to make sure you are driving the pin you think you are. Setting a signal to '1' should drive the pin high.
You can double check it too by driving a divided clock out and give yourself an edge to trigger a scope on.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;
ENTITY test IS
PORT (i_clk : IN std_logic;
i_reset : IN std_logic;
o_scope : OUT std_logic
);
END test;
ARCHITECTURE behv OF test IS
SIGNAL scope : std_logic;
BEGIN
p1 : PROCESS (i_clk, i_reset)
BEGIN
IF i_reset = RESET_LEVEL THEN
scope <= '0';
ELSIF clk'event AND clk = '1' THEN
scope <= NOT scope;
END IF;
END PROCESS p1;
o_scope <= scope;
END behv;
I have a problem with my vhdl code . In active-hdl it works perfectly , but when i tried to implement it on the FPGA board using ise design xilinx i have a problem with one component . The error i found is:
ERROR:Xst:827 - "E:/proiect_final/dispozitiv_impartitor/src/generator_square_wave.vhd" line 16: Signal numar_intermediar<0> cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity generator_square_wave is
port(clock,reset :in bit;
controler:std_logic_vector(2 downto 0);
numar:out std_logic_vector(7 downto 0);
data_clock:out bit);
end generator_square_wave ;
architecture descriere of generator_square_wave is
signal reset1:std_logic;
begin
process (clock,reset) -- here it shows me the error
variable numar_intermediar:bit_vector(3 downto 0 ):="0000";
variable numar_intermediar2:std_logic_vector(3 downto 0);
variable bitul:bit;
begin
reset1<=to_stdulogic(reset);
if rising_edge(reset1) then
numar_intermediar:="0001";
numar_intermediar2:=To_StdLogicVector(numar_intermediar);
numar(0)<=numar_intermediar2(0);
numar(1)<=numar_intermediar2(1);
numar(2)<=numar_intermediar2(2);
numar(3)<=numar_intermediar2(3);
numar(4)<='0';
numar(5)<='0';
numar(6)<='0';
numar(7)<='0';
else if( clock'event and clock ='1' and controler="001")then
bitul:=numar_intermediar(0);
numar_intermediar:=numar_intermediar srl 1;
numar_intermediar(3):=bitul;
numar_intermediar2:=To_StdLogicVector(numar_intermediar);
numar(0)<=numar_intermediar2(0);
numar(1)<=numar_intermediar2(1);
numar(2)<=numar_intermediar2(2);
numar(3)<=numar_intermediar2(3);
numar(4)<='0';
numar(5)<='0';
numar(6)<='0';
numar(7)<='0';
if(reset/='1' and controler/="001")then
numar<="00000000";
end if;
end if;
end if;
data_clock<=clock;
end process;
end descriere;
You have a few problems. First, you shouldn't be treating reset as a clock (i.e. using rising_edge()). If it's asynchronous, you should just write:
if reset1 = '1' then
...
The following line also has a problem (not sure if this is strictly illegal, but it's not recommended):
if( clock'event and clock ='1' and controler="001")then
This should be:
if clock'event and clock = '1' then
if controler = "001" then
(with additional end if to match.)
That should at least allow it to synthesize.
You may also want to make the statement reset1<=to_stdulogic(reset) concurrent instead of including it in the process, and there are a couple other possible changes you could make, but they're not as critical (unless I've missed something).