URL
https://opencores.org/ocsvn/yac/yac/trunk
Subversion Repositories yac
Compare Revisions
- This comparison shows the changes necessary to convert path
/yac
- from Rev 4 to Rev 5
- ↔ Reverse comparison
Rev 4 → Rev 5
/trunk/rtl/vhdl/cordic_iterative_wb.vhd
0,0 → 1,510
---------------------------------------------------------------------------- |
---- ---- |
---- File : cordic_iterative_wb.vhd ---- |
---- Project : YAC (Yet Another CORDIC Core) ---- |
---- Creation : Feb. 2014 ---- |
---- Limitations : ---- |
---- Synthesizer : ---- |
---- Target : ---- |
---- ---- |
---- Author(s): : Christian Haettich ---- |
---- Email : feddischson@opencores.org ---- |
---- ---- |
---- ---- |
----- ----- |
---- ---- |
---- Description ---- |
---- wb bus interface for the YAC ---- |
---- ---- |
---- ---- |
---- ---- |
----- ----- |
---- ---- |
---- Memory organization: ---- |
---- ----------------------------------------------------------- ---- |
---- | word | description | ---- |
---- | index | | ---- |
---- ----------------------------------------------------------- ---- |
---- | 0 | x_0 \ | ---- |
---- | 1 | y_0 \ 1'st entry | ---- |
---- | 2 | a_0 / | ---- |
---- | 3 | mode_0 / | ---- |
---- | 4 | x_1 \ | ---- |
---- | 5 | y_1 \ 2'nd entry | ---- |
---- | 6 | a_1 / | ---- |
---- | 7 | mode_1 / | ---- |
---- | 8 | . | ---- |
---- | | ... | ---- |
---- | N_ENTRIES*4-4 | x_n \ | ---- |
---- | N_ENTRIES*4-3 | y_n \ n'th entry | ---- |
---- | N_ENTRIES*4-2 | a_n / | ---- |
---- | N_ENTRIES*4-1 | mode_n / | ---- |
---- | N_ENTRIES*4 | status-register | ---- |
---- ----------------------------------------------------------- ---- |
---- ---- |
---- ---- |
---- Status register bit fields: ---- |
---- ---- |
---- bit 0: ==>> start/idle flag: ---- |
---- ------------------------------ ---- |
---- write 1: start ---- |
---- read 1: busy ---- |
---- read 0: idle ---- |
---- the flag is set by SW and cleared automatically ---- |
---- after processing. ---- |
---- ---- |
---- bit 1: ==>> IRQ flag: ---- |
---- ------------------------------ ---- |
---- write 1: sets the IRQ ---- |
---- write 0: clears the IRQ ---- |
---- the flag is set automatically by HW and is mapped ---- |
---- to irq_o. The software can clear the flag/irq by ---- |
---- writing a 0 to this bit. ---- |
---- ---- |
---- ---- |
---- ---- |
---- bit 16...ceil(log2(N_ENTRIES)): ==>> item-count ---- |
---- ----------------------------------------------- ---- |
---- defines, how much items are processed, ---- |
---- the processing works from the higher part to the lower ---- |
---- part of the memory. --- |
---- ---- |
---- ---- |
---- ---- |
---- ---- |
--------- ------------ |
---- TODO: ---- |
---- - further testing ---- |
---- - err_o: error output generation ---- |
---- ---- |
---- ---- |
---- ---- |
---- ---- |
---------------------------------------------------------------------------- |
---- ---- |
---- Copyright Notice ---- |
---- ---- |
---- This file is part of YAC - Yet Another CORDIC Core ---- |
---- Copyright (c) 2014, Author(s), All rights reserved. ---- |
---- ---- |
---- YAC 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 3.0 of the License, or (at your option) any later version. ---- |
---- ---- |
---- YAC 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 library. If not, download it from ---- |
---- http://www.gnu.org/licenses/lgpl ---- |
---- ---- |
---------------------------------------------------------------------------- |
|
|
|
library ieee; |
library std; |
use std.textio.all; |
use ieee.std_logic_1164.ALL; |
use ieee.numeric_std.ALL; |
use ieee.std_logic_textio.all; -- I/O for logic types |
use work.cordic_pkg.ALL; |
|
|
entity cordic_iterative_wb is |
generic( |
WB_ADR_WIDTH : natural := 32; -- wishbone address bus width |
N_ENTRIES : natural := 16; -- number of calculation entries, |
-- which can be stored |
A_WIDTH : natural := 12; -- \ |
XY_WIDTH : natural := 12; -- | Cordic setup |
GUARD_BITS : natural := 2; -- | |
RM_GAIN : natural := 3 -- / |
); |
port( |
clk_i : in std_logic; |
rst_i : in std_logic; |
dat_i : in std_logic_vector( 32-1 downto 0 ); |
dat_o : out std_logic_vector( 32-1 downto 0 ); |
adr_i : in std_logic_vector( WB_ADR_WIDTH-1 downto 0 ); |
we_i : in std_logic; |
sel_i : in std_logic_vector( 4-1 downto 0 ); |
cyc_i : in std_logic; |
stb_i : in std_logic; |
ack_o : out std_logic; |
cti_i : in std_logic_vector( 3-1 downto 0 ); |
bte_i : in std_logic_vector( 2-1 downto 0 ); |
irq_o : out std_logic |
); |
end entity; |
|
architecture IMP of cordic_iterative_wb is |
|
constant STATUS_REG_I : natural := N_ENTRIES*4; |
|
|
|
function ceil_log2(N: natural) return positive is |
begin |
if N <= 2 then |
return 1; |
else |
if N mod 2 = 0 then |
return 1 + ceil_log2( N/2 ); |
else |
return 1 + ceil_log2( (N+1) / 2 ); |
end if; |
end if; |
end; |
|
constant MEM_SIZE : natural := 32; |
-- |
-- memory blocks: |
-- N_ENTRIES * ( x, y, a, mode) + status-register |
-- |
type mem_t is array ( 0 to 4*N_ENTRIES+1-1 ) of std_logic_vector( MEM_SIZE-1 downto 0 ); |
signal MEM : mem_t; |
|
-- address size (in words) |
constant ADR_WIDTH : natural := ceil_log2( 4*N_ENTRIES+1 ); |
|
type B3_TRANS_T is ( WB_BURST, WB_NO_BURST ); |
signal b3_trans : B3_TRANS_T; |
signal addr : std_logic_vector( ADR_WIDTH-1 downto 0 ); |
signal addr_burst : std_logic_vector( ADR_WIDTH-1 downto 0 ); |
signal cti_r : std_logic_vector( cti_i'range ); |
signal bte_r : std_logic_vector( bte_i'range ); |
signal dat_o_tmp : std_logic_vector( dat_o'range ); |
signal wr_data : std_logic_vector( dat_i'range ); |
signal ack_r : std_logic; |
signal ack : std_logic; |
|
signal burst_start : std_logic; |
signal burst_end : std_logic; |
|
|
|
component cordic_iterative_int is |
generic( |
XY_WIDTH : natural := 12; |
A_WIDTH : natural := 12; |
GUARD_BITS : natural := 2; |
RM_GAIN : natural := 4 |
); |
port( |
clk, rst : in std_logic; |
en : in std_logic; |
start : in std_logic; |
done : out std_logic; |
mode_i : in std_logic_vector( 4-1 downto 0 ); |
x_i : in std_logic_vector( XY_WIDTH-1 downto 0 ); |
y_i : in std_logic_vector( XY_WIDTH-1 downto 0 ); |
a_i : in std_logic_vector( A_WIDTH+2-1 downto 0 ); |
x_o : out std_logic_vector( XY_WIDTH+GUARD_BITS-1 downto 0 ); |
y_o : out std_logic_vector( XY_WIDTH+GUARD_BITS-1 downto 0 ); |
a_o : out std_logic_vector( A_WIDTH+2-1 downto 0 ) |
); |
end component cordic_iterative_int; |
signal cordic_en : std_logic; |
signal cordic_start : std_logic; |
signal cordic_done : std_logic; |
signal cordic_mode_i : std_logic_vector( 4-1 downto 0 ); |
signal cordic_x_i : std_logic_vector( XY_WIDTH-1 downto 0 ); |
signal cordic_y_i : std_logic_vector( XY_WIDTH-1 downto 0 ); |
signal cordic_a_i : std_logic_vector( A_WIDTH+2-1 downto 0 ); |
signal cordic_x_o : std_logic_vector( XY_WIDTH+GUARD_BITS-1 downto 0 ); |
signal cordic_y_o : std_logic_vector( XY_WIDTH+GUARD_BITS-1 downto 0 ); |
signal cordic_a_o : std_logic_vector( A_WIDTH+2-1 downto 0 ); |
|
|
type state_T_st is (ST_IDLE, ST_START, ST_WAIT); |
type state_T is |
record |
st : state_T_st; |
cnt : unsigned( ceil_log2( N_ENTRIES ) -1 downto 0 ); |
end record; |
signal state : state_T; |
|
|
begin |
|
|
-- start of burst signal |
burst_start <= '1' when ( cti_i = "001" or cti_i = "010" ) |
and stb_i = '1' |
and b3_trans /= WB_BURST |
else '0'; |
|
-- end of burst signal |
burst_end <= '1' when cti_i = "111" |
and stb_i = '1' |
and b3_trans = WB_BURST |
and ack = '1' |
else '0'; |
|
|
|
|
------ |
-- Burst address generation: this depends on the number of entries |
-- and the internal address bus width |
-- |
BURST_GEN_ALL : if ADR_WIDTH > 4 generate |
addr_burst <= std_logic_vector( unsigned( addr ) + 1 ) when bte_r = "00" else |
addr( addr'high downto 2 ) & std_logic_vector( unsigned( addr( 1 downto 0 ) ) + 1 ) when bte_r = "01" else |
addr( addr'high downto 3 ) & std_logic_vector( unsigned( addr( 2 downto 0 ) ) + 1 ) when bte_r = "10" else |
addr( addr'high downto 4 ) & std_logic_vector( unsigned( addr( 3 downto 0 ) ) + 1 ) when bte_r = "11"; |
|
end generate; |
|
|
BURST_GEN_4 : if ADR_WIDTH = 4 generate |
addr_burst <= std_logic_vector( unsigned( addr ) + 1 ) when bte_r = "00" else |
addr( addr'high downto 2 ) & std_logic_vector( unsigned( addr( 1 downto 0 ) ) + 1 ) when bte_r = "01" else |
addr( addr'high downto 3 ) & std_logic_vector( unsigned( addr( 2 downto 0 ) ) + 1 ) when bte_r = "10" else |
std_logic_vector( unsigned( addr( 3 downto 0 ) ) + 1 ) when bte_r = "11"; |
end generate; |
|
|
BURST_GEN_3 : if ADR_WIDTH = 3 generate |
addr_burst <= std_logic_vector( unsigned( addr ) + 1 ) when bte_r = "00" else |
addr( addr'high downto 2 ) & std_logic_vector( unsigned( addr( 1 downto 0 ) ) + 1 ) when bte_r = "01" else |
std_logic_vector( unsigned( addr( 2 downto 0 ) ) + 1 ) when bte_r = "10"; |
end generate; |
|
|
BURST_GEN_2 : if ADR_WIDTH = 2 generate |
addr_burst <= std_logic_vector( unsigned( addr ) + 1 ) when bte_r = "00" else |
std_logic_vector( unsigned( addr( 1 downto 0 ) ) + 1 ) when bte_r = "01"; |
end generate; |
|
|
------ |
-- |
-- wishbone bus transaction handling |
-- - ack generation |
-- - burst handling |
-- - address handling |
-- |
p : process( clk_i, rst_i ) |
|
begin |
|
if clk_i'event and clk_i='1' then |
if rst_i = '1' then |
addr <= ( others => '0' ); |
b3_trans <= WB_NO_BURST; |
ack_r <= '0'; |
else |
|
cti_r <= cti_i; |
bte_r <= bte_i; |
|
|
if burst_start = '1' then |
addr <= adr_i( ADR_WIDTH+2-1 downto 2 ); |
|
elsif cti_r = "010" and ack = '1' and b3_trans = WB_BURST then |
addr <= addr_burst; |
else |
addr <= adr_i( ADR_WIDTH+2-1 downto 2 ); |
end if; |
|
|
if burst_start = '1' then |
|
-- start of burst |
b3_trans <= WB_BURST; |
|
elsif burst_end = '1' then |
|
-- end of burst |
b3_trans <= WB_NO_BURST; |
|
elsif b3_trans = WB_BURST then |
|
-- during burst |
|
end if; |
|
|
|
-- ack generation |
if cyc_i = '1' then |
|
if cti_i = "000" then |
|
if stb_i = '1' then |
ack_r <= not ack_r; |
end if; |
|
elsif cti_i = "010" or cti_i = "001" then |
ack_r <= stb_i; |
|
elsif cti_i = "111" then |
if ack_r = '0' then |
ack_r <= '1'; |
else |
ack_r <= '0'; |
end if; |
|
end if; |
else |
ack_r <= '0'; |
end if; |
|
end if; |
end if; |
|
end process; |
|
|
ack <= ack_r and stb_i; |
ack_o <= ack; |
|
wr_data( 31 downto 24 ) <= dat_i( 31 downto 24 ) when sel_i(3) = '1' else dat_o_tmp( 31 downto 24 ); |
wr_data( 23 downto 16 ) <= dat_i( 23 downto 16 ) when sel_i(2) = '1' else dat_o_tmp( 23 downto 16 ); |
wr_data( 15 downto 8 ) <= dat_i( 15 downto 8 ) when sel_i(1) = '1' else dat_o_tmp( 15 downto 8 ); |
wr_data( 7 downto 0 ) <= dat_i( 7 downto 0 ) when sel_i(0) = '1' else dat_o_tmp( 7 downto 0 ); |
|
|
--dat_o_tmp( dat_o_tmp'high downto MEM_SIZE ) <= ( others => '0' ); |
dat_o_tmp( MEM_SIZE-1 downto 0 ) <= MEM( to_integer( unsigned( addr ) ) ); |
dat_o <= dat_o_tmp; |
|
|
|
|
|
-- |
-- this includes a small state machine, the IRQ generation |
-- and the memory handling |
-- |
wr_p : process( clk_i, rst_i ) |
variable MEM_START : integer; |
begin |
|
if clk_i'event and clk_i='1' then |
if rst_i = '1' then |
MEM <= ( others => ( others => '0' ) ); |
state <= ( st => ST_IDLE, |
cnt => ( others => '0' ) ); |
|
cordic_start <= '0'; |
cordic_x_i <= ( others => '0' ); |
cordic_y_i <= ( others => '0' ); |
cordic_a_i <= ( others => '0' ); |
cordic_mode_i <= ( others => '0' ); |
|
else |
|
-- default values (get changed below) |
cordic_start <= '0'; |
cordic_x_i <= ( others => '0' ); |
cordic_y_i <= ( others => '0' ); |
cordic_a_i <= ( others => '0' ); |
cordic_mode_i <= ( others => '0' ); |
|
|
|
-- writing to memory |
if we_i = '1' and ack = '1' then |
MEM( to_integer( unsigned( addr ) ) ) <= wr_data( MEM_SIZE-1 downto 0 ); |
end if; |
|
|
|
|
-- start of all calculations |
if MEM( STATUS_REG_I )(0) = '1' and state.st = ST_IDLE then |
state.st <= ST_START; |
state.cnt <= unsigned( MEM( STATUS_REG_I )( 16+state.cnt'length-1 downto 16 ) )-1; |
end if; |
|
|
-- start of a single cordic calculation |
if state.st = ST_START then |
MEM_START := to_integer( state.cnt & "00" ); -- state.cnt * 4 |
cordic_x_i <= MEM( MEM_START+0 )( cordic_x_i'range ); |
cordic_y_i <= MEM( MEM_START+1 )( cordic_y_i'range ); |
cordic_a_i <= MEM( MEM_START+2 )( cordic_a_i'range ); |
cordic_mode_i <= MEM( MEM_START+3 )( cordic_mode_i'range ); |
cordic_start <= '1'; |
|
state.st <= ST_WAIT; |
end if; |
|
|
-- single cordic calculation is done: |
-- save the result and start the next one or |
-- go back to idle |
if state.st = ST_WAIT and cordic_done = '1' then |
MEM_START := to_integer( state.cnt & "00" ); -- state.cnt * 4 |
MEM( MEM_START+0 ) <= ( others => '0' ); |
MEM( MEM_START+1 ) <= ( others => '0' ); |
MEM( MEM_START+2 ) <= ( others => '0' ); |
MEM( MEM_START+0 )( cordic_x_o'range ) <= cordic_x_o; |
MEM( MEM_START+1 )( cordic_y_o'range ) <= cordic_y_o; |
MEM( MEM_START+2 )( cordic_a_o'range ) <= cordic_a_o; |
|
|
if state.cnt = 0 then |
|
-- go back to IDLE |
state.st <= ST_IDLE; |
|
-- clear busy flag |
MEM( STATUS_REG_I )( 0 ) <= '0'; |
|
-- set IRQ flag |
MEM( STATUS_REG_I )( 1 ) <= '1'; |
else |
state.st <= ST_START; |
state.cnt <= state.cnt-1; |
end if; |
|
end if; |
|
end if; |
end if; |
end process; |
|
-- disable the cordic when there is nothing to do |
cordic_en <= '0' when state.st = ST_IDLE else '1'; |
|
irq_o <= MEM( STATUS_REG_I )( 1 ); |
|
|
|
-- the cordic instance |
cordic_inst : cordic_iterative_int |
generic map ( |
XY_WIDTH => XY_WIDTH , |
A_WIDTH => A_WIDTH , |
GUARD_BITS => GUARD_BITS, |
RM_GAIN => RM_GAIN |
) |
port map( |
clk => clk_i , |
rst => rst_i , |
en => cordic_en , |
start => cordic_start , |
done => cordic_done , |
mode_i => cordic_mode_i , |
x_i => cordic_x_i , |
y_i => cordic_y_i , |
a_i => cordic_a_i , |
x_o => cordic_x_o , |
y_o => cordic_y_o , |
a_o => cordic_a_o |
); |
|
|
|
|
|
|
end architecture IMP; |