613 lines
18 KiB
VHDL
613 lines
18 KiB
VHDL
--------------------------------------------------------------------------------
|
|
-- light52_muldiv.vhdl -- Simple multiplier/divider module.
|
|
--------------------------------------------------------------------------------
|
|
-- The 8051 mul and div instructions are both unsigned and operands are 8 bit.
|
|
--
|
|
-- This module implements the division as a sequential state machine which takes
|
|
-- 8 cycles to complete.
|
|
-- The multiplier can be implemented as sequential or as combinational, in which
|
|
-- case it will use a DSP block in those architectures that support it.
|
|
-- No attempt has been made to make this module generic or reusable.
|
|
--
|
|
-- If you want a combinational multiplier but don't want to waste a DSP block
|
|
-- in this module, you need to modify this file adding whatever synthesis
|
|
-- pragmas your tool of choice needs.
|
|
--
|
|
-- Note that unlike the division state machine, the combinational product logic
|
|
-- is always operating: when SEQUENTIAL_MULTIPLIER=true, prod_out equals
|
|
-- data_a * data_b with a latency of 1 clock cycle, and mul_ready is hardwired
|
|
-- to '1'.
|
|
--
|
|
-- FIXME explain division algorithm.
|
|
--------------------------------------------------------------------------------
|
|
-- GENERICS:
|
|
--
|
|
-- SEQUENTIAL_MULTIPLIER -- Sequential vs. combinational multiplier.
|
|
-- When true, a sequential implementation will be used for the multiplier,
|
|
-- which will usually save a lot of logic or a dedicated multiplier.
|
|
-- When false, a combinational registered multiplier will be used.
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
-- INTERFACE SIGNALS:
|
|
--
|
|
-- clk : Clock, active rising edge.
|
|
-- reset : Synchronous reset. Clears only the control registers not
|
|
-- visible to the programmer -- not the output registers.
|
|
--
|
|
-- data_a : Numerator input, should be connected to the ACC register.
|
|
-- data_b : Denominator input, should be connected to the B register.
|
|
-- start : Assert for 1 cycle to start the division state machine
|
|
-- (and the product if SEQUENTIAL_MULTIPLIER=true);
|
|
--
|
|
-- prod_out : Product output, valid only when mul_ready='1'.
|
|
-- quot_out : Quotient output, valid only when div_ready='1'.
|
|
-- rem_out : Remainder output, valid only when div_ready='1'.
|
|
-- div_ov_out : Division overflow flag, valid only when div_ready='1'.
|
|
-- mul_ov_out : Product overflow flag, valid only when mul_ready='1'.
|
|
--
|
|
-- mul_ready : Asserted permanently if SEQUENTIAL_MULTIPLIER=false.
|
|
-- div_ready : Deasserted the cycle after start is asserted.
|
|
-- Asserted when the division has completed.
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
-- Copyright (C) 2012 Jose A. Ruiz
|
|
--
|
|
-- This source file may be used and distributed without
|
|
-- restriction provided that this copyright statement is not
|
|
-- removed from the file and that any derivative work contains
|
|
-- the original copyright notice and the associated disclaimer.
|
|
--
|
|
-- This source file is free software; you can redistribute it
|
|
-- and/or modify it under the terms of the GNU Lesser General
|
|
-- Public License as published by the Free Software Foundation;
|
|
-- either version 2.1 of the License, or (at your option) any
|
|
-- later version.
|
|
--
|
|
-- This source is distributed in the hope that it will be
|
|
-- useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
-- PURPOSE. See the GNU Lesser General Public License for more
|
|
-- details.
|
|
--
|
|
-- You should have received a copy of the GNU Lesser General
|
|
-- Public License along with this source; if not, download it
|
|
-- from http://www.opencores.org/lgpl.shtml
|
|
--------------------------------------------------------------------------------
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
use work.light52_pkg.all;
|
|
use work.light52_ucode_pkg.all;
|
|
|
|
entity light52_muldiv is
|
|
generic (
|
|
SEQUENTIAL_MULTIPLIER : boolean := false
|
|
);
|
|
port(
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
|
|
data_a : in t_byte;
|
|
data_b : in t_byte;
|
|
start : in std_logic;
|
|
|
|
prod_out : out t_word;
|
|
quot_out : out t_byte;
|
|
rem_out : out t_byte;
|
|
div_ov_out : out std_logic;
|
|
mul_ov_out : out std_logic;
|
|
|
|
mul_ready : out std_logic;
|
|
div_ready : out std_logic
|
|
);
|
|
end entity light52_muldiv;
|
|
|
|
architecture sequential of light52_muldiv is
|
|
|
|
signal bit_ctr : integer range 0 to 8;
|
|
|
|
signal b_shift_reg : t_word;
|
|
|
|
signal den_ge_256 : std_logic;
|
|
signal num_ge_den : std_logic;
|
|
signal sub_num : std_logic;
|
|
|
|
signal denominator : t_byte;
|
|
signal rem_reg : t_byte;
|
|
signal quot_reg : t_byte;
|
|
signal prod_reg : t_word;
|
|
signal ready : std_logic;
|
|
|
|
signal load_regs : std_logic;
|
|
|
|
begin
|
|
|
|
-- Control logic ---------------------------------------------------------------
|
|
|
|
control_counter: process(clk)
|
|
alias sig is <<signal g_test(0).i_test.sig : std_logic>>;
|
|
begin
|
|
if clk'event and clk='1' then
|
|
if reset='1' then
|
|
bit_ctr <= 8;
|
|
else
|
|
if load_regs='1' then
|
|
bit_ctr <= 0;
|
|
elsif bit_ctr /= 8 then
|
|
bit_ctr <= bit_ctr + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process control_counter;
|
|
|
|
-- Internal signal ready is asserted after 8 cycles.
|
|
-- The sequential multiplier will use this signal too, IF it takes 8 cycles.
|
|
|
|
ready <= '1' when bit_ctr >= 8 else '0';
|
|
|
|
|
|
---- Divider logic -------------------------------------------------------------
|
|
|
|
-- What we do is a simple base-2 'shift-and-subtract' algorithm that takes
|
|
-- 8 cycles to complete. We can get away with this because we deal with unsigned
|
|
-- numbers only.
|
|
|
|
divider_registers: process(clk)
|
|
begin
|
|
if clk'event and clk='1' then
|
|
-- denominator shift register
|
|
if load_regs='1' then
|
|
b_shift_reg <= "0" & data_b & "0000000";
|
|
-- Division overflow can be determined upon loading B reg data.
|
|
-- OV will be raised only on div-by-zero.
|
|
if data_b=X"00" then
|
|
div_ov_out <= '1';
|
|
else
|
|
div_ov_out <= '0';
|
|
end if;
|
|
else
|
|
b_shift_reg <= "0" & b_shift_reg(b_shift_reg'high downto 1);
|
|
end if;
|
|
|
|
-- numerator register
|
|
if load_regs='1' then
|
|
rem_reg <= data_a;
|
|
elsif bit_ctr/=8 and sub_num='1' then
|
|
rem_reg <= rem_reg - denominator;
|
|
end if;
|
|
|
|
--- quotient register
|
|
if load_regs='1' then
|
|
quot_reg <= (others => '0');
|
|
elsif bit_ctr/=8 then
|
|
quot_reg <= quot_reg(quot_reg'high-1 downto 0) & sub_num;
|
|
end if;
|
|
|
|
load_regs <= start;
|
|
end if;
|
|
end process divider_registers;
|
|
|
|
denominator <= b_shift_reg(7 downto 0);
|
|
|
|
-- The 16-bit comparison between b_shift_reg (denominator) and the zero-extended
|
|
-- rem_reg (numerator) can be simplified by splitting it in 2:
|
|
-- If the shifted denominator high byte is not zero, it is >=256...
|
|
den_ge_256 <= '1' when b_shift_reg(15 downto 8) /= X"00" else '0';
|
|
-- ...otherwise we need to compare the low bytes.
|
|
num_ge_den <= '1' when rem_reg >= denominator else '0';
|
|
sub_num <= '1' when den_ge_256='0' and num_ge_den='1' else '0';
|
|
|
|
|
|
quot_out <= quot_reg;
|
|
prod_out <= prod_reg;
|
|
rem_out <= rem_reg;
|
|
|
|
div_ready <= ready;
|
|
|
|
---- Multiplier logic ----------------------------------------------------------
|
|
|
|
---- Combinational multiplier -----------------------------
|
|
multiplier_combinational: if not SEQUENTIAL_MULTIPLIER generate
|
|
|
|
registered_combinational_multiplier:process(clk)
|
|
begin
|
|
if clk'event and clk='1' then
|
|
prod_reg <= data_a * data_b; -- t_byte is unsigned
|
|
end if;
|
|
end process registered_combinational_multiplier;
|
|
|
|
-- The multiplier output is valid in the cycle after the operands are loaded,
|
|
-- so by the time MUL is executed it's already done.
|
|
mul_ready <= '1';
|
|
|
|
mul_ov_out <= '1' when prod_reg(15 downto 8)/=X"00" else '0';
|
|
prod_out <= prod_reg;
|
|
|
|
end generate multiplier_combinational;
|
|
|
|
---- Sequential multiplier --------------------------------
|
|
multiplier_sequential: if SEQUENTIAL_MULTIPLIER generate
|
|
|
|
assert false
|
|
report "Sequential multiplier implementation not done yet."&
|
|
" Use combinational implementation."
|
|
severity failure;
|
|
|
|
end generate multiplier_sequential;
|
|
|
|
end sequential;
|
|
|
|
|
|
with Types; use Types;
|
|
with Files_Map;
|
|
|
|
package fixed_pkg is new IEEE.fixed_generic_pkg
|
|
generic map (
|
|
fixed_overflow_style => IEEE.fixed_float_types.fixed_saturate,
|
|
fixed_guard_bits => 3,
|
|
no_warning => false
|
|
);
|
|
|
|
package p is
|
|
type int_ptr is access integer;
|
|
type rec is record
|
|
data : std_logic_vector(31 downto 0);
|
|
ack : std_logic;
|
|
value : integer;
|
|
link : rec_ptr;
|
|
end record;
|
|
type int_vec is array (integer range <>) of integer;
|
|
type int_vec_ptr is access int_vec;
|
|
procedure UNIFORM(variable SEED1, SEED2 : inout POSITIVE; variable X : out REAL);
|
|
constant def_arr : t_int_array := (0 to 2 => 10);
|
|
|
|
-- type range
|
|
type newInt is range -4 to 3;
|
|
type CAPACITY is range 0 to 1E5 units
|
|
pF;
|
|
nF = 1000 pF;
|
|
end units;
|
|
|
|
-- type protected
|
|
type prot is protected
|
|
function meth(a : int) return bit;
|
|
end protected;
|
|
|
|
-- type protected body
|
|
type prot is protected body
|
|
variable var : positive;
|
|
constant const : boolean;
|
|
|
|
function meth(a : int) return bit is
|
|
begin
|
|
end function;
|
|
end protected body;
|
|
|
|
function \?=\ (L, R : BOOLEAN) return BOOLEAN;
|
|
|
|
end package;
|
|
|
|
package body p is
|
|
function \?=\ (L, R : BOOLEAN) return BOOLEAN is
|
|
begin
|
|
if not (format(format'left) = '%') then
|
|
report "to_string: Illegal format string """ & format & '"'
|
|
severity error;
|
|
return "";
|
|
end if;
|
|
return L = R;
|
|
end function \?=\;
|
|
|
|
procedure test is
|
|
variable v : int_ptr;
|
|
variable i : integer;
|
|
begin
|
|
v := null;
|
|
deallocate(v);
|
|
v := new integer;
|
|
v := new integer'(5);
|
|
v.all := 5;
|
|
r.all.value := 1;
|
|
a := new int_vec(1 to 3);
|
|
a.all(5) := 2;
|
|
a(1 to 2) := (1, 2);
|
|
s := new string'("");
|
|
end procedure;
|
|
|
|
procedure test2(x : inout rec_ptr) is
|
|
begin
|
|
x.value := x.value + 1;
|
|
end procedure;
|
|
|
|
procedure test3 is
|
|
type a;
|
|
type a is access integer;
|
|
variable v : a;
|
|
begin
|
|
end procedure;
|
|
|
|
type int_ptr_array is array (integer range <>) of int_ptr;
|
|
|
|
procedure tets4 is
|
|
type bvp is access bit_vector;
|
|
variable y : int_ptr(1 to 3) := int_ptr'(null);
|
|
begin
|
|
end procedure;
|
|
|
|
procedure Restore_Origin (Mark : Instance_Index_Type) is
|
|
begin
|
|
for I in reverse Mark + 1 .. Prev_Instance_Table.Last loop
|
|
declare
|
|
El : Instance_Entry_Type renames Prev_Instance_Table.Table (I);
|
|
begin
|
|
Origin_Table.Table (El.N) := El.Old_Origin;
|
|
end;
|
|
end loop;
|
|
Prev_Instance_Table.Set_Last (Mark);
|
|
end Restore_Origin;
|
|
|
|
-- Instantiate a list. Simply create a new list and instantiate nodes of
|
|
-- that list.
|
|
function Instantiate_Iir_List (L : Iir_List; Is_Ref : Boolean)
|
|
return Iir_List
|
|
is
|
|
Res : Iir_List;
|
|
El : Iir;
|
|
begin
|
|
case to_integer(unsigned(CTRL_REF(x*4+3 downto x*4))) is
|
|
when Null_Iir_List
|
|
| Iir_List_All =>
|
|
return L;
|
|
when others =>
|
|
It := List_Iterate (L);
|
|
while Is_Valid (It) loop
|
|
El := Get_Element (It);
|
|
Append_Element (Res, Instantiate_Iir (El, Is_Ref));
|
|
end loop;
|
|
for I in Flist_First .. Flist_Last (L) loop
|
|
Set_Nth_Element (Res, I, Instantiate_Iir (El, Is_Ref));
|
|
end loop;
|
|
return Res;
|
|
end case;
|
|
end Instantiate_Iir_List;
|
|
end package body;
|
|
|
|
-- Library bar
|
|
context foo.test_context;
|
|
|
|
context foo is
|
|
context foo.test_context;
|
|
end context foo;
|
|
|
|
entity concat is
|
|
end entity;
|
|
|
|
entity foo is
|
|
port (
|
|
x : in my_int );
|
|
end entity;
|
|
|
|
architecture t of concat is
|
|
type int_array is array (integer range <>) of integer;
|
|
type small is range 1 to 3;
|
|
|
|
component or_entity is
|
|
port(
|
|
input_1: in std_logic;
|
|
output: out std_logic
|
|
);
|
|
end component;
|
|
begin
|
|
process
|
|
variable s : string(1 to 5);
|
|
variable t : int_array(1 to 2);
|
|
variable c : bit_vector(1 to 4);
|
|
begin
|
|
x := ( 1, 2, 3 );
|
|
z := x & y;
|
|
w := 1 & x;
|
|
s := 'h' & string'("ello");
|
|
assert "10" = (b(1) & "0");
|
|
wait;
|
|
end process;
|
|
|
|
function CounterVal(Seconds : integer := 0) return integer is
|
|
variable TotalSeconds : interger;
|
|
begin
|
|
TotalSeconds := Seconds + Minutes * 60;
|
|
return TotalSeconds * ClockFrequencyHz -1;
|
|
end function;
|
|
|
|
type enum_type is (a, b, c, ..., z);
|
|
type int_array is array(3 downto 0) of integer;
|
|
|
|
subtype addr_int is integer range 0 to 65535;
|
|
subtype sub_enum_type is enum_type range a to m;
|
|
|
|
inst1: entity work.counter1(rtl)
|
|
generic map (BITS1 => 8)
|
|
port map (
|
|
clk1 => Clock,
|
|
DATA_OUT => pwm_data_o(3 downto 5),
|
|
COMP_IN(1 downto 0) => compensate_i,
|
|
WRITE_IN => (others => '0')
|
|
);
|
|
|
|
inst2: component counter2
|
|
generic map (BITS1 => 8)
|
|
port map (clk1 => Clock);
|
|
|
|
inst3: configuration counter3
|
|
generic map (BITS1 => 8)
|
|
port map (clk1 => Clock);
|
|
|
|
THE_PWM_GEN : pwm_generator
|
|
generic map(
|
|
dsfds => ds
|
|
)
|
|
port map(
|
|
CLK => clk_i,
|
|
DATA_IN => pwm_data_i,
|
|
DATA_OUT => pwm_data_o(3 downto 5),
|
|
COMP_IN(1 downto 0) => compensate_i,
|
|
WRITE_IN => (others => '0')
|
|
);
|
|
|
|
end architecture;
|
|
|
|
architecture a2 of e is
|
|
function ">"(a, b: my_int) return boolean;
|
|
begin
|
|
process is
|
|
variable x, y : my_int;
|
|
begin
|
|
assert x > y;
|
|
assert x < y; -- Error
|
|
end process;
|
|
|
|
billowitch_tc586: block is
|
|
type real_cons_vector is array (15 downto 0) of real;
|
|
type real_cons_vector_file is file of real_cons_vector;
|
|
constant C19 : real_cons_vector := (others => 3.0);
|
|
begin
|
|
end block;
|
|
end architecture;
|
|
|
|
architecture arch of ent is
|
|
begin
|
|
LL: if test=10 generate
|
|
begin
|
|
end;
|
|
elsif test=5 generate
|
|
begin
|
|
end;
|
|
end generate;
|
|
|
|
LL: if l1: SPEED = "fast" generate
|
|
elsif test=5 generate
|
|
end generate;
|
|
end architecture arch;
|
|
|
|
|
|
architecture thing_arch of designthing is
|
|
|
|
component pwm_generator
|
|
port(
|
|
CLK : in std_logic;
|
|
DATA_IN : in std_logic_vector(15 downto 0);
|
|
);
|
|
end component pwm_generator;
|
|
|
|
attribute NOM_FREQ : string;
|
|
attribute NOM_FREQ of clk_source : label is "133.00";
|
|
signal clk_i : std_logic;
|
|
|
|
begin
|
|
|
|
gen_no_comp: if TEMP = 0 generate
|
|
compensate_i <= (others => '0');
|
|
end generate;
|
|
|
|
gen_no_comp: for i in 0 to TEMP generate
|
|
compensate_i <= (others => '0') after 10 ns;
|
|
compensate_i <= (others => '0') ;
|
|
end generate;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- LED blinking when activity on inputs
|
|
---------------------------------------------------------------------------
|
|
PROC_TIMER : process begin
|
|
wait until rising_edge(clk_i);
|
|
timer <= timer + 1;
|
|
wait for 10 ns;
|
|
leds <= (last_inp xor inp_status(3 downto 0)) or leds or last_leds;
|
|
if timer = 0 then
|
|
leds <= not inp_status(3 downto 0);
|
|
last_leds <= x"0";
|
|
elsif gf then
|
|
fdsa <= '1';
|
|
end if;
|
|
|
|
xz: for x in 0 to 7 loop
|
|
dsadf;
|
|
end loop;
|
|
|
|
case c is
|
|
when XXX =>
|
|
c <= 1;
|
|
d <= 21321;
|
|
when YYYY =>
|
|
c <= 2;
|
|
end case;
|
|
end process;
|
|
|
|
|
|
generate_with_begin: if TEMP = 0 generate
|
|
signal : test : std_logic;
|
|
begin
|
|
compensate_i <= (others => '0');
|
|
if timer = 0 then
|
|
leds <= not inp_status(3 downto 0);
|
|
last_leds <= x"0";
|
|
elsif gf then
|
|
fdsa <= '1';
|
|
end if;
|
|
end generate generate_with_begin;
|
|
|
|
PROC_TIMER : process
|
|
variable x : std_logic;
|
|
begin
|
|
x := '0';
|
|
end process PROC_TIMER;
|
|
|
|
end architecture thing_arc; --this is not correct (wrong name)
|
|
|
|
1+1
|
|
2ns
|
|
|
|
1_2_3
|
|
12_3
|
|
1.2
|
|
1.2_3
|
|
1_3.2_3
|
|
12_3e+1
|
|
12_3e-1
|
|
12_3e1_1
|
|
12_3.4e1_1
|
|
12_3e1_
|
|
12_3e
|
|
|
|
2#1_2_3#E+8
|
|
2#1_2.3#E+8
|
|
2#1_f2.3#
|
|
|
|
3.14159_26536 -- A literal of type universal_real.
|
|
5280 -- A literal of type universal_integer.
|
|
10.7 ns -- A literal of a physical type.
|
|
O"4777" -- A bit string literal.
|
|
"54LS281" -- A string literal.
|
|
"" -- A string literal representing a null array.
|
|
B"1111_1111_1111" -- Equivalent to the string literal "111111111111".
|
|
X"FFF" -- Equivalent to B"1111_1111_1111".
|
|
O"777" -- Equivalent to B"111_111_111".
|
|
X"777" -- Equivalent to B"0111_0111_0111".
|
|
B"XXXX_01LH" -- Equivalent to the string literal "XXXX01LH"
|
|
UO"27" -- Equivalent to B"010_111"
|
|
UO"2C" -- Equivalent to B"011_CCC"
|
|
SX"3W" -- Equivalent to B"0011_WWWW"
|
|
D"35" -- Equivalent to B"100011"
|
|
12UB"X1" -- Equivalent to B"0000_0000_00X1"
|
|
12SB"X1" -- Equivalent to B"XXXX_XXXX_XXX1"
|
|
12UX"F-" -- Equivalent to B"0000_1111_----"
|
|
12SX"F-" -- Equivalent to B"1111_1111_----"
|
|
12D"13" -- Equivalent to B"0000_0000_1101"
|
|
12UX"000WWW" -- Equivalent to B"WWWW_WWWW_WWWW"
|
|
12SX"FFFC00" -- Equivalent to B"1100_0000_0000"
|
|
12SX"XXXX00" -- Equivalent to B"XXXX_0000_0000"
|
|
8D"511" -- Error
|
|
8UO"477" -- Error
|
|
8SX"0FF" -- Error
|
|
8SX"FXX" -- Error
|