1-------------------------------------------------------------------------------- 2-- light52_muldiv.vhdl -- Simple multiplier/divider module. 3-------------------------------------------------------------------------------- 4-- The 8051 mul and div instructions are both unsigned and operands are 8 bit. 5-- 6-- This module implements the division as a sequential state machine which takes 7-- 8 cycles to complete. 8-- The multiplier can be implemented as sequential or as combinational, in which 9-- case it will use a DSP block in those architectures that support it. 10-- No attempt has been made to make this module generic or reusable. 11-- 12-- If you want a combinational multiplier but don't want to waste a DSP block 13-- in this module, you need to modify this file adding whatever synthesis 14-- pragmas your tool of choice needs. 15-- 16-- Note that unlike the division state machine, the combinational product logic 17-- is always operating: when SEQUENTIAL_MULTIPLIER=true, prod_out equals 18-- data_a * data_b with a latency of 1 clock cycle, and mul_ready is hardwired 19-- to '1'. 20-- 21-- FIXME explain division algorithm. 22-------------------------------------------------------------------------------- 23-- GENERICS: 24-- 25-- SEQUENTIAL_MULTIPLIER -- Sequential vs. combinational multiplier. 26-- When true, a sequential implementation will be used for the multiplier, 27-- which will usually save a lot of logic or a dedicated multiplier. 28-- When false, a combinational registered multiplier will be used. 29-- 30-------------------------------------------------------------------------------- 31-- INTERFACE SIGNALS: 32-- 33-- clk : Clock, active rising edge. 34-- reset : Synchronous reset. Clears only the control registers not 35-- visible to the programmer -- not the output registers. 36-- 37-- data_a : Numerator input, should be connected to the ACC register. 38-- data_b : Denominator input, should be connected to the B register. 39-- start : Assert for 1 cycle to start the division state machine 40-- (and the product if SEQUENTIAL_MULTIPLIER=true); 41-- 42-- prod_out : Product output, valid only when mul_ready='1'. 43-- quot_out : Quotient output, valid only when div_ready='1'. 44-- rem_out : Remainder output, valid only when div_ready='1'. 45-- div_ov_out : Division overflow flag, valid only when div_ready='1'. 46-- mul_ov_out : Product overflow flag, valid only when mul_ready='1'. 47-- 48-- mul_ready : Asserted permanently if SEQUENTIAL_MULTIPLIER=false. 49-- div_ready : Deasserted the cycle after start is asserted. 50-- Asserted when the division has completed. 51-- 52-------------------------------------------------------------------------------- 53-- Copyright (C) 2012 Jose A. Ruiz 54-- 55-- This source file may be used and distributed without 56-- restriction provided that this copyright statement is not 57-- removed from the file and that any derivative work contains 58-- the original copyright notice and the associated disclaimer. 59-- 60-- This source file is free software; you can redistribute it 61-- and/or modify it under the terms of the GNU Lesser General 62-- Public License as published by the Free Software Foundation; 63-- either version 2.1 of the License, or (at your option) any 64-- later version. 65-- 66-- This source is distributed in the hope that it will be 67-- useful, but WITHOUT ANY WARRANTY; without even the implied 68-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 69-- PURPOSE. See the GNU Lesser General Public License for more 70-- details. 71-- 72-- You should have received a copy of the GNU Lesser General 73-- Public License along with this source; if not, download it 74-- from http://www.opencores.org/lgpl.shtml 75-------------------------------------------------------------------------------- 76 77library ieee; 78use ieee.std_logic_1164.all; 79use ieee.numeric_std.all; 80 81use work.light52_pkg.all; 82use work.light52_ucode_pkg.all; 83 84entity light52_muldiv is 85 generic ( 86 SEQUENTIAL_MULTIPLIER : boolean := false 87 ); 88 port( 89 clk : in std_logic; 90 reset : in std_logic; 91 92 data_a : in t_byte; 93 data_b : in t_byte; 94 start : in std_logic; 95 96 prod_out : out t_word; 97 quot_out : out t_byte; 98 rem_out : out t_byte; 99 div_ov_out : out std_logic; 100 mul_ov_out : out std_logic; 101 102 mul_ready : out std_logic; 103 div_ready : out std_logic 104 ); 105end entity light52_muldiv; 106 107architecture sequential of light52_muldiv is 108 109signal bit_ctr : integer range 0 to 8; 110 111signal b_shift_reg : t_word; 112 113signal den_ge_256 : std_logic; 114signal num_ge_den : std_logic; 115signal sub_num : std_logic; 116 117signal denominator : t_byte; 118signal rem_reg : t_byte; 119signal quot_reg : t_byte; 120signal prod_reg : t_word; 121signal ready : std_logic; 122 123signal load_regs : std_logic; 124 125begin 126 127-- Control logic --------------------------------------------------------------- 128 129control_counter: process(clk) 130begin 131 if clk'event and clk='1' then 132 if reset='1' then 133 bit_ctr <= 8; 134 else 135 if load_regs='1' then 136 bit_ctr <= 0; 137 elsif bit_ctr /= 8 then 138 bit_ctr <= bit_ctr + 1; 139 end if; 140 end if; 141 end if; 142end process control_counter; 143 144-- Internal signal ready is asserted after 8 cycles. 145-- The sequential multiplier will use this signal too, IF it takes 8 cycles. 146 147ready <= '1' when bit_ctr >= 8 else '0'; 148 149 150---- Divider logic ------------------------------------------------------------- 151 152-- What we do is a simple base-2 'shift-and-subtract' algorithm that takes 153-- 8 cycles to complete. We can get away with this because we deal with unsigned 154-- numbers only. 155 156divider_registers: process(clk) 157begin 158 if clk'event and clk='1' then 159 -- denominator shift register 160 if load_regs='1' then 161 b_shift_reg <= "0" & data_b & "0000000"; 162 -- Division overflow can be determined upon loading B reg data. 163 -- OV will be raised only on div-by-zero. 164 if data_b=X"00" then 165 div_ov_out <= '1'; 166 else 167 div_ov_out <= '0'; 168 end if; 169 else 170 b_shift_reg <= "0" & b_shift_reg(b_shift_reg'high downto 1); 171 end if; 172 173 -- numerator register 174 if load_regs='1' then 175 rem_reg <= data_a; 176 elsif bit_ctr/=8 and sub_num='1' then 177 rem_reg <= rem_reg - denominator; 178 end if; 179 180 --- quotient register 181 if load_regs='1' then 182 quot_reg <= (others => '0'); 183 elsif bit_ctr/=8 then 184 quot_reg <= quot_reg(quot_reg'high-1 downto 0) & sub_num; 185 end if; 186 187 load_regs <= start; 188 end if; 189end process divider_registers; 190 191denominator <= b_shift_reg(7 downto 0); 192 193-- The 16-bit comparison between b_shift_reg (denominator) and the zero-extended 194-- rem_reg (numerator) can be simplified by splitting it in 2: 195-- If the shifted denominator high byte is not zero, it is >=256... 196den_ge_256 <= '1' when b_shift_reg(15 downto 8) /= X"00" else '0'; 197-- ...otherwise we need to compare the low bytes. 198num_ge_den <= '1' when rem_reg >= denominator else '0'; 199sub_num <= '1' when den_ge_256='0' and num_ge_den='1' else '0'; 200 201 202quot_out <= quot_reg; 203prod_out <= prod_reg; 204rem_out <= rem_reg; 205 206div_ready <= ready; 207 208---- Multiplier logic ---------------------------------------------------------- 209 210---- Combinational multiplier ----------------------------- 211multiplier_combinational: if not SEQUENTIAL_MULTIPLIER generate 212 213registered_combinational_multiplier:process(clk) 214begin 215 if clk'event and clk='1' then 216 prod_reg <= data_a * data_b; -- t_byte is unsigned 217 end if; 218end process registered_combinational_multiplier; 219 220-- The multiplier output is valid in the cycle after the operands are loaded, 221-- so by the time MUL is executed it's already done. 222mul_ready <= '1'; 223 224mul_ov_out <= '1' when prod_reg(15 downto 8)/=X"00" else '0'; 225prod_out <= prod_reg; 226 227end generate multiplier_combinational; 228 229---- Sequential multiplier -------------------------------- 230multiplier_sequential: if SEQUENTIAL_MULTIPLIER generate 231 232assert false 233report "Sequential multiplier implementation not done yet."& 234 " Use combinational implementation." 235severity failure; 236 237end generate multiplier_sequential; 238 239end sequential; 240 241 242with Types; use Types; 243with Files_Map; 244 245package p is 246 type int_ptr is access integer; 247 type rec is record 248 value : integer; 249 link : rec_ptr; 250 end record; 251 type int_vec is array (integer range <>) of integer; 252 type int_vec_ptr is access int_vec; 253 constant def_arr : t_int_array := (0 to 2 => 10); 254end package; 255 256package body p is 257 procedure test is 258 variable v : int_ptr; 259 variable i : integer; 260 begin 261 v := null; 262 deallocate(v); 263 v := new integer; 264 v := new integer'(5); 265 v.all := 5; 266 r.all.value := 1; 267 a := new int_vec(1 to 3); 268 a.all(5) := 2; 269 a(1 to 2) := (1, 2); 270 s := new string'(""); 271 end procedure; 272 273 procedure test2(x : inout rec_ptr) is 274 begin 275 x.value := x.value + 1; 276 end procedure; 277 278 procedure test3 is 279 type a; 280 type a is access integer; 281 variable v : a; 282 begin 283 end procedure; 284 285 type int_ptr_array is array (integer range <>) of int_ptr; 286 287 procedure tets4 is 288 type bvp is access bit_vector; 289 variable y : int_ptr(1 to 3) := int_ptr'(null); 290 begin 291 end procedure; 292 293 procedure Restore_Origin (Mark : Instance_Index_Type) is 294 begin 295 for I in reverse Mark + 1 .. Prev_Instance_Table.Last loop 296 declare 297 El : Instance_Entry_Type renames Prev_Instance_Table.Table (I); 298 begin 299 Origin_Table.Table (El.N) := El.Old_Origin; 300 end; 301 end loop; 302 Prev_Instance_Table.Set_Last (Mark); 303 end Restore_Origin; 304 305 -- Instantiate a list. Simply create a new list and instantiate nodes of 306 -- that list. 307 function Instantiate_Iir_List (L : Iir_List; Is_Ref : Boolean) 308 return Iir_List 309 is 310 Res : Iir_List; 311 El : Iir; 312 begin 313 case L is 314 when Null_Iir_List 315 | Iir_List_All => 316 return L; 317 when others => 318 It := List_Iterate (L); 319 while Is_Valid (It) loop 320 El := Get_Element (It); 321 Append_Element (Res, Instantiate_Iir (El, Is_Ref)); 322 end loop; 323 for I in Flist_First .. Flist_Last (L) loop 324 Set_Nth_Element (Res, I, Instantiate_Iir (El, Is_Ref)); 325 end loop; 326 return Res; 327 end case; 328 end Instantiate_Iir_List; 329end package body; 330 331-- Library bar 332context foo.test_context; 333 334entity concat is 335end entity; 336 337entity foo is 338 port ( 339 x : in my_int ); 340end entity; 341 342architecture t of concat is 343 type int_array is array (integer range <>) of integer; 344begin 345 process 346 variable s : string(1 to 5); 347 variable t : int_array(1 to 2); 348 variable c : bit_vector(1 to 4); 349 begin 350 x := ( 1, 2, 3 ); 351 z := x & y; 352 w := 1 & x; 353 s := 'h' & string'("ello"); 354 assert "10" = (b(1) & "0"); 355 wait; 356 end process; 357 358 function CounterVal(Seconds : integer := 0) return integer is 359 variable TotalSeconds : interger; 360 begin 361 TotalSeconds := Seconds + Minutes * 60; 362 return TotalSeconds * ClockFrequencyHz -1; 363 end function; 364 365 component or_entity is 366 port( 367 input_1: in std_logic; 368 output: out std_logic 369 ); 370 end component; 371 372 type enum_type is (a, b, c, ..., z); 373 type int_array is array(3 downto 0) of integer; 374 375 subtype addr_int is integer range 0 to 65535; 376 subtype sub_enum_type is enum_type range a to m; 377end architecture; 378 379architecture a2 of e is 380 function ">"(a, b: my_int) return boolean; 381begin 382 process is 383 variable x, y : my_int; 384 begin 385 assert x > y; 386 assert x < y; -- Error 387 end process; 388 389 billowitch_tc586: block is 390 type real_cons_vector is array (15 downto 0) of real; 391 type real_cons_vector_file is file of real_cons_vector; 392 constant C19 : real_cons_vector := (others => 3.0); 393 begin 394 end block; 395end architecture; 396