5 DESIGN AV FIR-FILTER
6.3 PS/2 PORT
7.3.5 Filter_muls
Det finns tre sådana block och i dessa sker multiplikationerna av
filterkoefficienterna och insignal.
När signalen load är låg så laddas x_in och c_in i x- respektive c-registret.
Sedan sker multiplikationen mellan dessa värden och produkten läggs på
utsignalen y1. När en multiplikation är klar så skickas en ready signal.
Figur 7.6
7.3.6
Adder
Ready signalen i detta block är sammankopplad med ready signalen från
multiplier modulen. När denna signal blir låg så sparas det tidigare inkommande
värdet z_in i register s. Efter att detta har inträffats så adderas värdet i register s
och in_add. Efter denna addition läggs summan ut på utsignalen ut.
7.3.7
Adder2
Adder2 fungerar på liknade sätt som adder men den har ingen ready signal. Det
gör att ett inkommande värde(z_in) sparas i register s utan att någon ready
signal sätts. Sedan läggs produkten från multiplier på in_add och adderas till sist
med värdet i s och läggs på utsignalen ut.
Figur 7.8
7.3.8
Store
I detta block skall produkten av x_in. När signalen ready är låg så sparas det
inkommande värdet från in_data i register z. Därefter så läggs värdet ut på
utsignalen ut_data.
8
Avslutning
I detta avsnitt diskuteras arbetet och resultaten redovisas.
8.1
Resultat CORDIC
Simuleringarna utförda i Matlab skilde sig jämfört med resultaten från
utförandet på XSA-50 kortet.
Andledningen till detta är att hårdvaruutförandet av CORDIC-framåtrotationen
bara kan utföra ett fåtal iterationer, så kan det uppstå vissa felaktigheter. De
uppmätta värdena från hårdvaruutförandet av programmet kan även skilja sig
från de simulerade värdena på grund av avrundningsfel. Detta beror på att man i
hårdvaran endast kan jobba med heltal.
Matlabprogram som har skrivits skapar den nödvändiga HEX filen, som behövs
för att ladda ner det valda x-värdet på SDRAM:en. Detta underlättar då man
slipper räkna ut checksumovärdena som är nödvändiga.
Vidare har det skapts en manual som kan användas vid självstudier av bland
annat implementering av CORDIC-algoritmen och SDRAM funktionen på
XSA-50 kortet.
8.2
Resultat FIR
Efter att simuleringsresultatet i Matlab har jämförts med det på hårdvaran så
kunde det konstateras att implementeringen var lyckad. Filtret fungerade enligt
förutsättningarna.
Utsignalen y[n] visades på olika sätt vid simulering respektive
hårdvaruimplementering. I Matlab visades multiplikationerna av insignalen och
filterkoefficienterna var för sig. Medan det på hårdvaran är summan av samtliga
multiplikationer som visas.
Vidare har det skapts en manual som kan användas vid självstudier av bland
annat implementering av FIR-filter och tangentbordsfunktionen på XSA-50
kortet.
8.3
Problem
8.4
Diskussion
CORDIC-algoritmen är väl anpassad till att användas på DSP tillämpningar. Då
den till största delen handlar om addition och skiftoperationer. I detta arbete så
har algoritmen anpassats till att fungerar med XSA-50 kortet. Detta har fungerat
väl då laborationskortet har många funktioner som kan utnyttjas. I CORDIC
tillämpningen så används den inbyggda SDRAM:en. Genom att utgå från detta
projekt kan man lätt använda SDRAM till egna projekt och tillämpningar.
Vid konstruktionen av FIR filtret så utfördes simulation i Matlab, detta
underlättade vidare arbete med konstruktionen på XSA-50 kortet.
Blockkonstruktion tillämpades med stor fördel. Detta gjorde det mycket enklare
att skapa en bra översikt över de olika delarna i filtret. Felsökning av FIR filtret
underlättades avsevärt, då varje block kunde simuleras var för sig. För denna
del av projektet har PS/2 ingången använts för inläsning ifrån tangentbordet.
Detta projekt kan vara en utgångspunkt för att anpassa tangentbordsinläsning
till egna tillämpningar.
9
Terminologi
Akrynom
Förklaring
CLB
Configurable Logic Block
CORDIC
COordinate Rotation DIgital Computer
CS
Carry Signal
DCORDIC
Differential CORDIC
DFT
Discrete Fourier Transform
DSP
Digital Signal Processor
DTFT
Discrete Time Fourier Transform
FA
Full Adder
FFT
Fast Fourier Transform
FIR
Finite Impulse Response
FPGA
Field Programmable Gate Array
IIR
Infinite Impulse Response
IOB
Input Output Block
LSB
Least Significant Bit
LTI
Linear Time Invariant
LUT
Look-Up Tables
MSB
Most Significant Bit
10
Referenser
1. J.E. Volder, "The CORDIC Trigonometric Computing Technique," IRE
Trans Electronic Computers, vol8, pp. 330-334, Sept. 1959.
2. J. S. Walther, "A Unified Algorithm for Elementary Functions," Proc.
Spring. Joint Computer Conf., pp. 379-385, 1971.
3. R. Andraka, “A Survey of CORDIC Algorithms for FPGAs,” in
Proceedings of the 1998 ACM/SIGDA Sixth International Symposium on
Field Programmable Gate Arrays (FPGA ’98),Monterey, CA, Feb. 22–24,
1998, pp. 191–200.
4. J.E. Volder, ”The Birth of CORDIC”, 2000
5. D. Timmermann (1990): “CORDIC-Algorithmen, Architekturen und
monolithische Realisierungen mit Anwendungen in der Bildverarbeitung,”
Ph.D. thesis, VDI/Springer, Düsseldorf, Vol. 10, No. 152
6. H. Hahn (1991): “Untersuchung und Integration von Berechnungsverfahren
elementarer Funktionen auf CORDIC-Basis mit Anwendungen in der
adaptiven Signalverarbeitung,” Ph.D. thesis, VDI/Springer, Düsseldorf, Vol.
9, No. 125
7. U. Meyer-Bäse: The Use of Complex Algorithm in the Realization of
Universal Sampling Receiver Using FPGAs (in German) (VDI/Springer,
Düsseldorf, 1995), Vol. 10, No.404, 215 pages
8. U. Meyer-Bäse, A. Meyer-Bäse, W. Hilberg: “ COordinate Rotation DIgital
Computer (CORDIC) Synthesis for FPGA,” Lecture Notes in Computer
Science 849, 397-408 (Springer, Heidelberg, 1994)
9.
J. Valls, M. Kuhlmann, K.K. Parhi, “Evaluation of CORDIC Algorithms for
FPGA Design,“ Journal of VLSI Signal Processing 32, pp. 207-222, 2002.
10.
H. Dawid and H. Meyr, “The Differential CORDIC Algorithm: Constant
Scale Factor Redundant Implementation without Correcting Iterations,”
12.
N. Takagi, T. Asada, and S.Yajima, “Redundant CORDIC Methods with a
Constant Scale Factor for Sine and Cosine Computation,” IEEE
Transactions on Computers, vol. 40, no. 9, 1991.
13.
J.-A. Lee andT. Lang, “Constant-Factor RedundantCORDICfor Angle
Calculation and Rotation,” IEEE Transactions on Computers, vol. 41, no. 8,
1992.
14.
Shen-Fu Hsiao and Jean-Marc Delosme, “Householder CORDIC
Algorithm,” IEEE Transactions on Computers, vol. 44, no. 8, 1995.
15.
Shen-Fu Hsiao and Jen-Yin Chen, “Design, Implementation and Analysis of
aNewRedundant CORDIC Processor with Constant Scaling Factor and
Regular Structure,” Journal of VLSI Signal Processing, vol. 20, 1998, pp.
267–278.
16.
Shen-Fu, Hsiao, “A High-Speed Constant-Factor Redundant CORDIC
Processor without Extra Correcting or Scaling Iterations,” in IEEE Int. Conf.
On Circuits and Systems (ISCAS’99), Florida, 1999.
17.
H. Dawid and H. Meyr, “The Differential CORDIC Algorithm: Constant
Scale Factor Redundant implementation without Correcting Iterations,”
IEEE Transactions on Computers, vol. 45, no. 3, 1996.
18.
M. Kuhlmann and K.K. Parhi, “A High-Speed CORDIC Algorithm and
Architecture for DPS Applications,” in Proc. of the 1999 IEEE Workshop
on Signal Processing Systems (SiPS’99), Taipei, Taiwan, Oct. 1999.
19.
M. Kuhlmann and K.K. Parhi, “A New CORDIC Rotation Method for
Generalized Coodinate Systems,” in Proc. of the 1999 Asilomar Conference
on Signal, Systems and Computers, Pacific Grove, CA, Oct. 1999.
20.
P.A. Lynn, W. Fuerst, ”Introductory Digital Signal Processing” 1994
21.R.M. Mersereau, M.J.T. Smith, ”Digital Filtering” 1994
22.
U.M. Baese,”Dgital Signal Processing with Field Programmable Gate
Arrays” 2001
23.
O. Pedersen, ”Signaler och System kompendium för teori och praktik”, mars
2003, 2:a editionen.
-- Filename Ps2_kbd.vhd
--- -- This circuit accepts a serial datastream and clock from a PS/2 keyboard
-- and outputs the scancode for any key that is pressed. --
-- Notes: --
-- 1. The clock from the PS/2 keyboard does not drive the clock inputs of -- any of the registers in this circuit. Instead, it is sampled at the
-- frequency of the main clock input and edges are extracted from the samples. -- So you have to apply a main clock that is substantially faster than
-- the 10 KHz PS/2 clock. It should be 200 KHz or more. --
-- 2. The scancode is only valid when the ready signal is high. The scancode -- should be registered by an external circuit on the first clock edge -- after the ready signal goes high.
--
-- 3. The ready signal pulses only after the key is released. --
-- 4. The error flag is set whenever the PS/2 clock stops pulsing and the -- PS/2 clock is either at a low level or less than 11 bits of serial -- data have been received (start + 8 data + parity + stop). The circuit -- locks up once an error is detected and will not resume operation until -- a reset is applied. library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; package ps2_kbd_pckg is component ps2_kbd generic(
FREQ : natural := 100_000 -- frequency of the main clock (KHz) );
port(
clk : in std_logic; -- main clock
rst : in std_logic; -- asynchronous reset
ps2_clk : in std_logic; -- clock from keyboard
ps2_data : in std_logic; -- data from keyboard
scancode : out std_logic_vector(7 downto 0); -- key scancode
rdy : out std_logic; -- scancode ready pulse
error : out std_logic -- error receiving scancode
);
end component ps2_kbd; end package ps2_kbd_pckg;
library IEEE;
scancode : out std_logic_vector(7 downto 0); -- key scancode rdy : out std_logic; -- scancode ready pulse error : out std_logic -- error receiving scancode );
end entity ps2_kbd;
architecture arch of ps2_kbd is
--constant FREQ : natural := 100_000; constant YES : std_logic := '1'; constant NO : std_logic := '0';
constant PS2_FREQ : natural := 10; -- keyboard clock frequency (KHz) constant TIMEOUT : natural := FREQ / PS2_FREQ; -- ps2_clk quiet timeout
constant KEY_RELEASE : std_logic_vector(7 downto 0) := "11110000"; -- scancode sent when key is released
signal timer_x, timer_r : natural range 0 to TIMEOUT; -- counts time since last PS/2 clock edge signal bitcnt_x, bitcnt_r : natural range 0 to 11; -- counts number of received scancode bits signal ps2_clk_x, ps2_clk_r : std_logic_vector(5 downto 1); -- PS/2 clock synchronization / edge detect
-- shift register
signal ps2_clk_fall_edge : std_logic; -- pulses on falling edge of PS/2 clock signal ps2_clk_rise_edge : std_logic; -- pulses on rising edge of PS/2 clock signal ps2_clk_edge : std_logic; -- pulses on either edge of PS/2 clock signal ps2_clk_quiet : std_logic; -- pulses when no edges on PS/2 clock for TIMEOUT signal sc_x, sc_r : std_logic_vector(9 downto 0); -- scancode shift register
signal keyrel_x, keyrel_r : std_logic; -- this flag is set when the key release scancode is received signal scancode_rdy : std_logic; -- indicates when any scancode has been received
signal rdy_x, rdy_r : std_logic; -- this flag is set when scancode for the pressed key is ready signal error_x, error_r : std_logic; -- this flag is set when an error occurs
begin
-- shift the level on the PS/2 clock into a shift register ps2_clk_x <= ps2_clk_r(4 downto 1) & ps2_clk;
-- look at the PS/2 clock levels stored in the shift register and find rising or falling edges ps2_clk_fall_edge <= YES when ps2_clk_r(5 downto 2) = "1100" else NO;
ps2_clk_rise_edge <= YES when ps2_clk_r(5 downto 2) = "0011" else NO; ps2_clk_edge <= ps2_clk_fall_edge or ps2_clk_rise_edge;
-- shift the keyboard scancode into the shift register on the falling edge of the PS/2 clock sc_x <= ps2_data & sc_r(9 downto 1) when ps2_clk_fall_edge = YES else sc_r;
-- clear the timer right after a PS/2 clock edge and then keep incrementing it until the next edge timer_x <= 0 when ps2_clk_edge = YES else timer_r + 1;
-- indicate when the PS/2 clock has stopped pulsing and is at a high level.
ps2_clk_quiet <= YES when timer_r = TIMEOUT and ps2_clk_r(2) = '1' else NO;
-- increment the bit counter on each falling edge of the PS/2 clock.
-- reset the bit counter if the PS/2 clock stops pulsing or if there was an error receiving the scancode. -- otherwise, keep the bit counter unchanged.
NO when rdy_r = YES or error_r = YES else keyrel_r;
-- the scancode for the pressed key arrives after receiving the key-release scancode rdy_x <= YES when keyrel_r = YES and scancode_rdy = YES else NO;
-- indicate an error if the clock is low for too long or if it stops pulsing in the middle of a scancode error_x <= YES when (timer_r = TIMEOUT and ps2_clk_r(2) = '0') or
(ps2_clk_quiet = YES and bitcnt_r/=11 and bitcnt_r/=0) else error_r;
scancode <= sc_r(scancode'range); -- output scancode
-- parity <= sc_r(scancode'high+1); -- output parity bit for the scancode
-- busy <= YES when bitcnt_r/=0 else NO; -- output busy signal when receiving a scancode rdy <= rdy_r; -- output scancode ready flag
error <= error_r; -- output error flag
-- update the various registers process(rst, clk)
begin
if rst = YES then
ps2_clk_r <= (others => '1'); -- start by assuming PS/2 clock has been high for a while sc_r <= (others => '0'); -- clear scancode register
keyrel_r <= NO; -- key-release scancode has not been received yet rdy_r <= NO; -- no scancodes received yet
timer_r <= 0; -- clear PS/2 clock pulse timer bitcnt_r <= 0; -- clear scancode bit counter error_r <= NO; -- clear any errors
elsif rising_edge(clk) then ps2_clk_r <= ps2_clk_x; sc_r <= sc_x; keyrel_r <= keyrel_x; rdy_r <= rdy_x; timer_r <= timer_x; bitcnt_r <= bitcnt_x; error_r <= error_x; end if; end process;
end architecture arch;
--- --Filename Keyb_scan.vhd --- -- tangentbordsavkodning. library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
error : in std_logic;
x_ut : out std_logic_vector (7 downto 0)); end keyb_scan;
architecture Behavioral of keyb_scan is constant YES : std_logic := '1'; constant NO : std_logic := '0';
constant DIG_1 : std_logic_vector(7 downto 0) := "00000001"; constant DIG_2 : std_logic_vector(7 downto 0) := "00000010"; constant DIG_3 : std_logic_vector(7 downto 0) := "00000011"; constant DIG_4 : std_logic_vector(7 downto 0) := "00000100"; constant DIG_5 : std_logic_vector(7 downto 0) := "00000101"; constant DIG_6 : std_logic_vector(7 downto 0) := "00000110"; constant DIG_7 : std_logic_vector(7 downto 0) := "00000111"; constant DIG_8 : std_logic_vector(7 downto 0) := "00001000"; constant DIG_9 : std_logic_vector(7 downto 0) := "00001001"; constant DIG_0 : std_logic_vector(7 downto 0) := "00000000"; constant LETTER_E : std_logic_vector(7 downto 0) := "00000000";
signal s_x : std_logic_vector(7 downto 0);
begin
s_x <= DIG_1 when scancode = "00010110" else DIG_2 when scancode = "00011110" else
DIG_3 when scancode = "00100110" else DIG_4 when scancode = "00100101" else DIG_5 when scancode = "00101110" else DIG_6 when scancode = "00110110" else DIG_7 when scancode = "00111101" else DIG_8 when scancode = "00111110" else DIG_9 when scancode = "01000110" else DIG_0 when scancode = "01000101" else LETTER_E;
process(clk) begin
if rising_edge(clk) then if rdy = YES then
x_ut<=s_x; -- update the display each time a scancode is received end if; end if; end process; end Behavioral; --- --Filename loadbuff.vhd --- -- laddar in alla koefficienter och invärdet från tangentbordet.
library IEEE;
Port ( clk : in std_logic; load : in std_logic; res : in std_logic;
x_in : in std_logic_vector(7 downto 0); x_ut : out std_logic_vector(7 downto 0); c_ut1 : out std_logic_vector(7 downto 0); c_ut2 : out std_logic_vector(7 downto 0); c_ut3 : out std_logic_vector(7 downto 0); ready : out std_logic);
end loadbuff;
architecture Behavioral of loadbuff is
signal c_in1,c_in2,c_in3 : std_logic_vector(7 downto 0); begin
process(res,clk) begin
if res='1' and load=’0’ then -- när res är hög så sätt samtliga koefficienter ready<='1';
c_in1 <="00000001"; c_in2 <="00000010"; c_in3 <="00000001";
c_ut1 <="00000000"; -- och alla utvärden nollställs c_ut2 <="00000000";
c_ut3 <="00000000"; x_ut <="00000000";
elsif clk='1' and clk'event then
if load='1' and res=’0’ then -- när load är hög så ladda koefficienterna och
c_ut1 <=c_in1; -- värdet från tangentbordet in i registerna
c_ut2 <=c_in2; c_ut3 <=c_in3; x_ut <=x_in; ready<='0';
elsif load=’0’ and res=’0’ then ready<='1'; end if; end if; end process; end Behavioral; --- --Filename filter+muls.vhd --- -- multiplicerar koefficienten med invärdet.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following lines to use the declarations that are -- provided for instantiating Xilinx primitive components. --library UNISIM;
architecture Behavioral of filter_muls is type state_type is (s0, s1, s2, s3, s4);
signal state: state_type;
signal c,x: std_logic_vector(7 downto 0);
begin
process(res,clk)
variable p: std_logic_vector(15 downto 0); variable t : std_logic_vector(7 downto 0);
variable count : integer range 0 to 7;
begin
if res ='1' then -- när res är hög så nollställs registerna
x<="00000000"; c<="00000000";
y1<="0000000000000000"; elsif clk = '1' and clk'event then
if load='0' then -- när load är låg så laddas x och c registerna
x<=x_in; c<=c_in; state<=s1; else case state is when s0=> ready<='1'; state<=s0;
when s1 => -- påbörja multiplicering
state <= s2; count :=0; p :="0000000000000000"; t :=x; when s2 => if count = 7 then state <= s3; else if c(count) = '1' then p := p + t; end if; t := t+t; count := count +1; state <= s2; end if; when s3 => ready<='0'; y1<=p; state <= s4; when s4 => state <=s0; end case;
use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following lines to use the declarations that are -- provided for instantiating Xilinx primitive components. --library UNISIM;
--use UNISIM.VComponents.all;
entity adder is
Port ( in_add : in std_logic_vector(15 downto 0); res : in std_logic;
z_in : in std_logic_vector(16 downto 0); ut : out std_logic_vector(17 downto 0); ready : in std_logic;
clk : in std_logic); end adder;
architecture Behavioral of adder is signal s : std_logic_vector(16 downto 0); begin
process(clk,res) begin
if res ='1' then
s<="00000000000000000"; -- när res är hög så nollställs s-registret
elsif clk='1' and clk'event then
if ready='0' then -- när ready är låg så sparas det tidigare värdet i s
s<=z_in; end if;
ut <=s+in_add; -- adderar invärdet och s samt lägger på utgång
end if; end process; end Behavioral; --- --Filename adder2.vhd --- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following lines to use the declarations that are -- provided for instantiating Xilinx primitive components. --library UNISIM;
--use UNISIM.VComponents.all;
entity adder2 is
Port ( in_add : in std_logic_vector(15 downto 0); Res : in std_logic;
z_in : in std_logic_vector(15 downto 0); ut : out std_logic_vector(16 downto 0);
s<=z_in;
ut <=s+in_add; -- adderar och lägger ut på utgången
end if; end process; end Behavioral; --- --Filename store.vhd --- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following lines to use the declarations that are -- provided for instantiating Xilinx primitive components. --library UNISIM; --use UNISIM.VComponents.all; entity store is Port ( clk : in std_logic; ready : in std_logic; res : in std_logic;
in_data : in std_logic_vector(15 downto 0); ut_data : out std_logic_vector(15 downto 0)); end store;
architecture Behavioral of store is signal z: std_logic_vector(15 downto 0); begin
process(clk,res) begin
if res ='1' then -- när res är hög så nollställs z registret
z<="0000000000000000"; elsif clk='1' and clk'event then
if ready='0' then -- när ready är låg sparas invärdet i z
z<=in_data; end if;
ut_data<=z; -- lägger ut z på utgången
end if;
end process; end Behavioral;
--- -- Filename: sdramtst50.vhd
---
library IEEE, UNISIM; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use UNISIM.VComponents.all; use WORK.common.all; use WORK.mem.all; use WORK.xsasdram.all;
-- synchronous DRAM tester
entity sdramTst50 is
generic(
FREQ: natural := 100_000; -- frequency of operation in KHz
PIPE_EN: boolean:= TRUE; -- enable fast, pipelined SDRAM operation
DATA_WIDTH:natural := 16; -- SDRAM data width
BEG_ADDR: natural := 16#00_0000#; -- beginning SDRAM address END_ADDR: natural := 16#3F_FFFF#; -- ending SDRAM address BEG_TEST: natural := 16#00_0000#; -- beginning test range address END_TEST: natural := 16#3F_FFFF# -- ending test range address );
port(
ce_n: out std_logic; -- Flash RAM chip-enable
pushb_n: in std_logic; -- active-low pushbutton input
clk: in std_logic; -- main clock input from external clock source sclkfb: in std_logic; -- feedback SDRAM clock with PCB delays sclk: out std_logic; -- clock to SDRAM
cke: out std_logic; -- SDRAM clock-enable
cs_n: out std_logic; -- SDRAM chip-select
ras_n: out std_logic; -- SDRAM RAS
cas_n: out std_logic; -- SDRAM CAS
we_n: out std_logic; -- SDRAM write-enable
ba: out unsigned( 1 downto 0); -- SDRAM bank-address
sAddr: out unsigned(11 downto 0); -- SDRAM address bus sData: inout unsigned(DATA_WIDTH-1 downto 0); -- data bus to/from
-- SDRAM
dqmh: out std_logic; -- SDRAM DQMH
dqml: out std_logic; -- SDRAM DQML
s: out unsigned(6 downto 0); -- 7-segment LED
pps: out std_logic_vector(6 downto 3) -- outputs to parallel port -- status bits
);
end sdramTst50;
signal hAddr: unsigned(ADDR_WIDTH-1 downto 0); -- host address bus
signal hDIn: unsigned(DATA_WIDTH-1 downto 0); -- host-side data to SDRAM signal hDOut: unsigned(DATA_WIDTH-1 downto 0); -- host-side data from SDRAM
signal rd: std_logic; -- host-side read control signal
signal wr: std_logic; -- host-side write control signal
signal dataIn: unsigned(DATA_WIDTH-1 downto 0); -- input databus from SDRAM signal dataOut: unsigned(DATA_WIDTH-1 downto 0); -- output databus to SDRAM signal divCnt: unsigned(22 downto 0); -- clock divider
signal progress: std_logic_vector(1 downto 0); -- test progress indicator