I'm wondering what the correct way to handle the following situation is. Sorry this is a bit long winded. BTW, it's not homework, all that was 40+ years ago. I have two clocks, clk which is the FPGA clock rate, and sclk which I create using a simple divide by n counter. Typically, sclk is 1024 times slower than clk. An event occurs that sets a reg, DR, for one clk cycle. There is a register, calcreg [7:0] which is to be incremented slowly, but reset to zero on DR. There are two sections, one triggered by clk and one by sclk, ie: // Fast section always @ (posedge clk) begin .... end // Slow section always @ (posedge sclk) begin if (DR) calcreg <= 8'h0 ; // Reset calcreg on DR else calcreg <= calcreg + 1 ; // Else increment end The problem of course is that the on state of DR will almost always be missed, it will only appear if it happens to coincide with a sclk edge (1 / 1024). So the above doesn't work. So I tried modifying the clk section as follows: always @ (posedge clk) begin .... if (DR) calcreg <= 8'h0 ; end This threw up build errors, Error (10028): Can't resolve multiple constant drivers for net "FlashCtr[3]" at tick.v(43) I think I see the reason, it's like trying to wire two gate outputs to the same point, something that's obviously verboten with active drive hardware. If someone could help with the following specific questions it would help a lot..... Is using the two clocks simply bad practice, ie. should everything be done in a single always block at clk rate? Is there a standard way to latch the DR signal when it occurs on the fast clock, so that it will be there on the next transition of sclk, which must then clear the DR latch? I've tried this, and come up with the same build error with the latch.
Fast and slow clocks
Started by ●October 18, 2014
Reply by ●October 18, 20142014-10-18
Hi, I would put it all into a single clk block. I.e. reg [9:0] count = 0; always @(posedge clk) begin count <= count + 1; // fast "clock" here if (count == 0) begin end end Depending on what you want to achieve, you could also re-synchronize the --------------------------------------- Posted through http://www.FPGARelated.com
Reply by ●October 18, 20142014-10-18
.. you could also resynchronize the slow "clock" on the event. Maybe the difficulty is to define how exactly the circuit is going to behave, not so much coding it in RTL. Multiple clocks might be used on an ASIC where it allows use of smaller cells for the slow part. For a simple FPGA project, my main goal would be to keep the code as readable as possible. --------------------------------------- Posted through http://www.FPGARelated.com
Reply by ●October 18, 20142014-10-18
On 10/18/2014 3:53 AM, "Bruce Varley" wrote:> I'm wondering what the correct way to handle the following situation > is. Sorry this is a bit long winded. BTW, it's not homework, all that > was 40+ years ago. > > > I have two clocks, clk which is the FPGA clock rate, and sclk which I > create using a simple divide by n counter. Typically, sclk is 1024 > times slower than clk. > > An event occurs that sets a reg, DR, for one clk cycle. > > There is a register, calcreg [7:0] which is to be incremented slowly, > but reset to zero on DR. > > There are two sections, one triggered by clk and one by sclk, ie: > > // Fast section > always @ (posedge clk) > begin > .... > end > > // Slow section > always @ (posedge sclk) > begin > if (DR) calcreg <= 8'h0 ; // Reset calcreg on DR > else calcreg <= calcreg + 1 ; // Else increment > end > > The problem of course is that the on state of DR will almost always be > missed, it will only appear if it happens to coincide with a sclk edge > (1 / 1024). So the above doesn't work. > > So I tried modifying the clk section as follows: > > always @ (posedge clk) > begin > .... > if (DR) calcreg <= 8'h0 ; > end > > This threw up build errors, > > Error (10028): Can't resolve multiple constant drivers for net > "FlashCtr[3]" at tick.v(43) > > I think I see the reason, it's like trying to wire two gate outputs to > the same point, something that's obviously verboten with active drive > hardware. > > > If someone could help with the following specific questions it would > help a lot..... > > Is using the two clocks simply bad practice, ie. should everything be > done in a single always block at clk rate? > > Is there a standard way to latch the DR signal when it occurs on the > fast clock, so that it will be there on the next transition of sclk, > which must then clear the DR latch? I've tried this, and come up with > the same build error with the latch. >If you're really just dividing one clock to make another, then you're probably better off using a single clock and generating a count enable for your slow process. On the other hand your problem of using a fast signal to reset a slow process is also applicable to situations where the two clocks are not related and are both necessary for the design. In that case I would normally have an intermediate variable in the fast clock domain that gets set by DR and cleared by a signal returned from the slow process. Something like: reg DR_hold = 0; reg DR_seen = 0; always @ (posedge clk) begin if (DR) DR_hold <= 1; else if (DR_resync) DR_hold <= 0; end always @ (posedge sclk) begin DR_resync <= DR_hold; end Note that if you use DR_resync as the reset term, it will cause additional latency from DR to the reset of the counter. You could use DR_hold instead, but then the problem is if the two clocks are really unrelated you could miss a reset if DR_hold asserts very near the rising edge of sclk and DR_resync catches the event but the counter (or some of its bits) does not. -- Gabor
Reply by ●October 18, 20142014-10-18
On 10/18/2014 10:53 AM, Gabor wrote:> On 10/18/2014 3:53 AM, "Bruce Varley" wrote: >> I'm wondering what the correct way to handle the following situation >> is. Sorry this is a bit long winded. BTW, it's not homework, all that >> was 40+ years ago. >> >> >> I have two clocks, clk which is the FPGA clock rate, and sclk which I >> create using a simple divide by n counter. Typically, sclk is 1024 >> times slower than clk. >> >> An event occurs that sets a reg, DR, for one clk cycle. >> >> There is a register, calcreg [7:0] which is to be incremented slowly, >> but reset to zero on DR. >> >> There are two sections, one triggered by clk and one by sclk, ie: >> >> // Fast section >> always @ (posedge clk) >> begin >> .... >> end >> >> // Slow section >> always @ (posedge sclk) >> begin >> if (DR) calcreg <= 8'h0 ; // Reset calcreg on DR >> else calcreg <= calcreg + 1 ; // Else increment >> end >> >> The problem of course is that the on state of DR will almost always be >> missed, it will only appear if it happens to coincide with a sclk edge >> (1 / 1024). So the above doesn't work. >> >> So I tried modifying the clk section as follows: >> >> always @ (posedge clk) >> begin >> .... >> if (DR) calcreg <= 8'h0 ; >> end >> >> This threw up build errors, >> >> Error (10028): Can't resolve multiple constant drivers for net >> "FlashCtr[3]" at tick.v(43) >> >> I think I see the reason, it's like trying to wire two gate outputs to >> the same point, something that's obviously verboten with active drive >> hardware. >> >> >> If someone could help with the following specific questions it would >> help a lot..... >> >> Is using the two clocks simply bad practice, ie. should everything be >> done in a single always block at clk rate? >> >> Is there a standard way to latch the DR signal when it occurs on the >> fast clock, so that it will be there on the next transition of sclk, >> which must then clear the DR latch? I've tried this, and come up with >> the same build error with the latch. >> > > If you're really just dividing one clock to make another, then you're > probably better off using a single clock and generating a count enable > for your slow process. On the other hand your problem of using a fast > signal to reset a slow process is also applicable to situations where > the two clocks are not related and are both necessary for the design. > In that case I would normally have an intermediate variable in the fast > clock domain that gets set by DR and cleared by a signal returned from > the slow process. Something like: > > reg DR_hold = 0; > reg DR_seen = 0; > always @ (posedge clk) > begin > if (DR) DR_hold <= 1; > else if (DR_resync) DR_hold <= 0; > end > > always @ (posedge sclk) > begin > DR_resync <= DR_hold; > end > > Note that if you use DR_resync as the reset term, it will > cause additional latency from DR to the reset of the counter. > You could use DR_hold instead, but then the problem is if > the two clocks are really unrelated you could miss a reset > if DR_hold asserts very near the rising edge of sclk and > DR_resync catches the event but the counter (or some of its > bits) does not. >Oops, in the previous post I started with "DR_seen" but then went to "DR_resync" for the same signal. But you get the idea... -- Gabor
Reply by ●October 18, 20142014-10-18
Okay, you ain't going to like VHDL, but here is a solution based on a Johns= on ring divider: ---------------------------------------------------------------------------= ---------------------------------------------------------------------------= ---------- -- File : wrapper_SPI_Master.vhd -- Author : David Greig (email : dgreig@ieee.org) -- Revision : -- Description : ---------------------------------------------------------------------------= --------------------------------------------- -- Notes : --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- entity wrapper_SPI_Master is port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic; cpol_i : in std_logic; cpha_i : in std_logic; spi_wr_i : in std_logic;-----------------------------------------------= ---------------------------------------------------------------------------= -------------------------------------- -- File : wrapper_SPI_Master.vhd -- Author : David Greig (email : dgreig@ieee.org) -- Revision : -- Description : ---------------------------------------------------------------------------= --------------------------------------------- -- Notes : --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- entity wrapper_SPI_Master is port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic; cpol_i : in std_logic; cpha_i : in std_logic; spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(16-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic; spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(16-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic; sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end entity wrapper_SPI_Master; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- architecture rtl of wrapper_SPI_Master is ---------------------------------------------------------------------------= --------------------------------------------- component SPI_Master generic( Gram_pref : string; Gfifo_depth : natural; Gdwidth : natural; Gspi_clk_div : natural ); port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic; cpol_i : in std_logic; cpha_i : in std_logic; spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(Gdwidth-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic; spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(Gdwidth-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic; sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end component SPI_Master; ---------------------------------------------------------------------------= --------------------------------------------- begin ---------------------------------------------------------------------------= --------------------------------------------- inst_SPI_Master : SPI_Master generic map( Gram_pref =3D> "logic", Gfifo_depth =3D> 2, Gdwidth =3D> 16, Gspi_clk_div =3D> 4 ) port map( arstn =3D> arstn , clk =3D> clk , spi_rst_i =3D> spi_rst_i , clken =3D> clken , cpol_i =3D> cpol_i , cpha_i =3D> cpha_i , spi_wr_i =3D> spi_wr_i , spi_tx_data_i =3D> spi_tx_data_i , spi_tx_empty_o =3D> spi_tx_empty_o , spi_tx_full_o =3D> spi_tx_full_o , spi_tx_ovf_o =3D> spi_tx_ovf_o , spi_tx_unf_o =3D> spi_tx_unf_o , spi_tx_done_o =3D> spi_tx_done_o , spi_rd_i =3D> spi_rd_i , spi_rx_data_o =3D> spi_rx_data_o , spi_rx_empty_o =3D> spi_rx_empty_o , spi_rx_full_o =3D> spi_rx_full_o , spi_rx_ovf_o =3D> spi_rx_ovf_o , spi_rx_unf_o =3D> spi_rx_unf_o , sck_o =3D> sck_o , ssn_o =3D> ssn_o , mosi_o =3D> mosi_o , miso_i =3D> miso_i ); ---------------------------------------------------------------------------= --------------------------------------------- end architecture rtl; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- spi_tx_data_i : in std_logic_vector(16-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic; spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(16-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic; sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end entity wrapper_SPI_Master; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- architecture rtl of wrapper_SPI_Master is ---------------------------------------------------------------------------= --------------------------------------------- component SPI_Master generic( Gram_pref : string; Gfifo_depth : natural; Gdwidth : natural; Gspi_clk_div : natural ); port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic; cpol_i : in std_logic; cpha_i : in std_logic; spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(Gdwidth-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic; spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(Gdwidth-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic; sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end component SPI_Master; ---------------------------------------------------------------------------= --------------------------------------------- begin ---------------------------------------------------------------------------= --------------------------------------------- inst_SPI_Master : SPI_Master generic map( Gram_pref =3D> "logic", Gfifo_depth =3D> 2, Gdwidth =3D> 16, Gspi_clk_div =3D> 4 ) port map( arstn =3D> arstn , clk =3D> clk , spi_rst_i =3D> spi_rst_i , clken =3D> clken , cpol_i =3D> cpol_i , cpha_i =3D> cpha_i , spi_wr_i =3D> spi_wr_i , spi_tx_data_i =3D> spi_tx_data_i , spi_tx_empty_o =3D> spi_tx_empty_o , spi_tx_full_o =3D> spi_tx_full_o , spi_tx_ovf_o =3D> spi_tx_ovf_o , spi_tx_unf_o =3D> spi_tx_unf_o , spi_tx_done_o =3D> spi_tx_done_o , spi_rd_i =3D> spi_rd_i , spi_rx_data_o =3D> spi_rx_data_o , spi_rx_empty_o =3D> spi_rx_empty_o , spi_rx_full_o =3D> spi_rx_full_o , spi_rx_ovf_o =3D> spi_rx_ovf_o , spi_rx_unf_o =3D> spi_rx_unf_o , sck_o =3D> sck_o , ssn_o =3D> ssn_o , mosi_o =3D> mosi_o , miso_i =3D> miso_i ); ---------------------------------------------------------------------------= --------------------------------------------- end architecture rtl; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- ---------------------------------------------------------------------------= ---------------------------------------------------------------------------= ---------- -- File : SPI_Master.vhd -- Author : David Greig (email : dgreig@ieee.org) -- Revision : -- Description : SPI master with individual fifo buffers on RX and TX ---------------------------------------------------------------------------= --------------------------------------------- -- Notes : -- Verified conforming with "Freescale Semiconductor, Inc." SPI Block Guide= V4 S12SPIV4.pdf -- cpha 0 means "sample on 1st edge", cpha =3D 1 means "sample on 2nd edge"= . -- cpol simply changes the effective polarity of the clock -- Tranfer latency - ssn goes low 2 clk cycles after first spi_wr -- One complete sck period is inserted between ssn falling edge to data sta= rt, and again from data end to ssn rising edge, and again at the end to giv= e minimum -- ssn high of one sck period -- Illustration for 8 bit data :- overall time =3D (nbits + 3) * sck period= s -- sck ~_______________________/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF= =AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\_= ____________~ -- cpol=3D0 ssn ~=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF\______________________= _________________________________________________________/=AF=AF=AF=AF=AF~ -- cpha=3D0 sdo ~-------------------X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D= =3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3D= X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX--------= -----~ -- sck ~=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF= =AF=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/= =AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF= =AF=AF~ -- cpol=3D1 ssn ~=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF\______________________= _________________________________________________________/=AF=AF=AF=AF=AF~ -- cpha=3D0 sdo ~-------------------X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D= =3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3D= X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX--------= -----~ -- -- sck ~___________________/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\= ___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\_____= ____________~ -- cpol=3D0 ssn ~=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF\______________________= _________________________________________________________/=AF=AF=AF=AF=AF~ -- cpha=3D1 sdo ~-------------------X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D= =3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3D= X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX--------= ----- -- -- sck ~=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF\= ___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF\___/= =AF=AF=AF\___/=AF=AF=AF\___/=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF= =AF=AF~ -- cpol=3D1 ssn ~=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF=AF\______________________= _________________________________________________________/=AF=AF=AF=AF=AF~ -- cpha=3D1 sdo ~-------------------X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D= =3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3D= X=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX=3D=3D=3D=3D=3D=3D=3DX--------= -----~ -- -- FSM ^S0_IDLE ^S1_STRT^S2_CLK ^S2_CLK ^S2_CLK ^S2_CLK ^S2_CLK ^= S2_CLK ^S2_CLK ^S2_CLK ^S3_END ^S4_CSHI^ -- --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- entity SPI_Master is generic( Gram_pref : string; -- fifo ram type Gfifo_depth : positive; -- fifo length =3D 2**Gdepth Gdwidth : positive; -- fifo data width Gspi_clk_div : positive -- spi clock divider, >=3D2 and an even number ); port( arstn : in std_logic; clk : in std_logic; clken : in std_logic; spi_rst_i : in std_logic; -- reset the spi logic cpol_i : in std_logic; -- spi bus clock polarity "Freescale Semi= conductor, Inc." SPI Block Guide V4 S12SPIV4.pdf cpha_i : in std_logic; -- spi bus clock phase "Freescale Semicon= ductor, Inc." SPI Block Guide V4 S12SPIV4.pdf spi_wr_i : in std_logic; -- write strobe spi_tx_data_i : in std_logic_vector(Gdwidth-1 downto 0); -- write data spi_tx_empty_o : out std_logic; -- write empty, ready to accept da= ta spi_tx_full_o : out std_logic; -- write full, will not accept new = data spi_tx_ovf_o : out std_logic; -- write overflowed spi_tx_unf_o : out std_logic; -- write underflowed spi_tx_done_o : out std_logic; -- write finished xmitting last wor= d spi_rd_i : in std_logic; -- read strobe spi_rx_data_o : out std_logic_vector(Gdwidth-1 downto 0); -- read data spi_rx_empty_o : out std_logic; -- read empty spi_rx_full_o : out std_logic; -- read full spi_rx_ovf_o : out std_logic; -- read overflow spi_rx_unf_o : out std_logic; -- read underflow sck_o : out std_logic; -- spi bus clock ssn_o : out std_logic; -- spi bus slave select, active low mosi_o : out std_logic; -- spi bus master out, slave in, tristat= e when inactive miso_i : in std_logic -- spi bus master in, slave out ); end entity SPI_Master; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- architecture rtl of SPI_Master is --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- attribute syn_encoding : string; -- FSM type synthesis encoding --------------------------------------------------------------------------= ---------------------------------------------- component Cnt_Ring_Rst generic( Glen : positive ); port( arstn : in std_logic; clk : in std_logic; clken : in std_logic; cnt_rstn_i : in std_logic; q_o : out std_logic_vector(Glen - 1 downto 0) ); end component Cnt_Ring_Rst; --------------------------------------------------------------------------= ------ signal spi_clk_cnt_s : std_logic_vector(Gspi_clk_div - 1 downto 0); signal spi_rst_r : std_logic; signal spi_clk_rstn_r : std_logic; signal spi_cyc_cnt_r : natural range (Gdwidth*Gspi_clk_div) downto 0 :=3D= 0; signal sck_r : std_logic; signal ssn_r : std_logic; signal tx_pop_r : std_logic; signal tx_empty_s : std_logic; signal rx_push_r : std_logic; signal tx_data_s : std_logic_vector(Gdwidth-1 downto 0); signal txs_r : std_logic_vector(Gdwidth-1 downto 0); signal rxs_r : std_logic_vector(Gdwidth-1 downto 0); --------------------------------------------------------------------------= ------ type FSMspi_t is (S0_IDLE, S1_STRT, S2_CLK, S3_END, S4_CSHI); attribute sy= n_encoding of FSMspi_t : type is "safe, one-hot"; signal FSMspi : FSMspi_t; --------------------------------------------------------------------------= ------ component SPI_Fifo generic( Gram_type : string; -- fifo ram type Gdepth : positive; -- fifo length =3D 2**Gdepth Gdwidth : positive -- fifo data width ); port( arstn : in std_logic; clken : in std_logic; clk : in std_logic; fifo_rst : in std_logic; -- reset the fifo pointer to the start push_i : in std_logic; -- push data in to fifo data_i : in std_logic_vector(Gdwidth - 1 downto 0); -- push data in full_o : out std_logic; -- push fifo full ovf_o : out std_logic; -- push fifo overflow pop_i : in std_logic; -- pop data out of fifo data_o : out std_logic_vector(Gdwidth - 1 downto 0); -- pop data out empty_o : out std_logic; -- pop fifo empty unf_o : out std_logic -- pop fifo underflow ); end component SPI_Fifo; ---------------------------------------------------------------------------= --------------------------------------------- begin ---------------------------------------------------------------------------= --------------------------------------------- -- parameter checks assert Gfifo_depth >=3D 2 report "Gfifo_depth must be greater or equal to = 2 (fifo size =3D 2**Gfifo_depth)" severity failure; assert Gspi_clk_div >=3D 4 report "Gspi_clk_div must be greater or equal t= o 4 and an even number" severity failure; assert (Gspi_clk_div mod 2) =3D 0 report "Gspi_clk_div must an even number= (also must be >=3D4)" severity failure; --------------------------------------------------------------------------= ---------------------------------------------- -- Johnson counter i_Cnt_Ring_Rst : Cnt_Ring_Rst generic map( Glen =3D> Gspi_clk_div ) port map( arstn =3D> arstn, clk =3D> clk, clken =3D> clken, cnt_rstn_i =3D> spi_clk_rstn_r, q_o =3D> spi_clk_cnt_s ); --------------------------------------------------------------------------= ---------------------------------------------- -- FSM controlling transfer prcs_FSMspi : process(arstn, clk) begin if (arstn =3D '0') then spi_rst_r <=3D '0'; FSMspi <=3D s0_idle; spi_clk_rstn_r <=3D '0'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0';-- xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D (others =3D> '0'); ssn_r <=3D '1'; spi_tx_done_o <=3D '0'; elsif (rising_edge(clk)) then spi_rst_r <=3D spi_rst_i; case FSMspi is when S0_IDLE =3D> if (tx_empty_s =3D '0') then FSMspi <=3D S1_STRT; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D (others =3D> '0'); ssn_r <=3D '0'; spi_tx_done_o <=3D '0'; else FSMspi <=3D S0_IDLE; spi_clk_rstn_r <=3D '0'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D (others =3D> '0'); ssn_r <=3D '1'; spi_tx_done_o <=3D '0'; end if; when S1_STRT =3D> if (spi_clk_cnt_s(0) =3D '1') then FSMspi <=3D S2_CLK; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; ---------------------------------------- if (cpha_i =3D '1') then if ((spi_clk_cnt_s(spi_clk_cnt_s'high) =3D '1') or (spi_clk_cnt_s(0)= =3D '1')) then sck_r <=3D '1' xor cpol_i; elsif (spi_clk_cnt_s((Gspi_clk_div/2)) =3D '1') then sck_r <=3D '0' xor cpol_i; else sck_r <=3D sck_r; end if; else sck_r <=3D '0' xor cpol_i; end if; ---------------------------------------- tx_pop_r <=3D '1'; rx_push_r <=3D '0'; txs_r <=3D tx_data_s; rxs_r <=3D rxs_r; ssn_r <=3D '0'; spi_tx_done_o <=3D '0'; else FSMspi <=3D S1_STRT; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D txs_r; rxs_r <=3D rxs_r; ssn_r <=3D '0'; spi_tx_done_o <=3D '0'; end if; when S2_CLK =3D> if (spi_cyc_cnt_r < (Gdwidth*Gspi_clk_div)-1) then FSMspi <=3D S2_CLK; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D spi_cyc_cnt_r + 1; ---------------------------------------- if (cpha_i =3D '1') then if ((spi_clk_cnt_s(spi_clk_cnt_s'high) =3D '1') or (spi_clk_cnt_s(0)= =3D '1')) then sck_r <=3D '1' xor cpol_i; elsif (spi_clk_cnt_s((Gspi_clk_div/2)) =3D '1') then sck_r <=3D '0' xor cpol_i; else sck_r <=3D sck_r; end if; else if ((spi_clk_cnt_s(spi_clk_cnt_s'high) =3D '1') or (spi_clk_cnt_s(0)= =3D '1')) then sck_r <=3D '0' xor cpol_i; elsif (spi_clk_cnt_s((Gspi_clk_div/2)) =3D '1') then sck_r <=3D '1' xor cpol_i; else sck_r <=3D sck_r; end if; end if; ---------------------------------------- tx_pop_r <=3D '0'; rx_push_r <=3D '0'; ---------------------------------------- if (spi_clk_cnt_s(0) =3D '1') then txs_r <=3D txs_r(txs_r'high-1 downto 0) & '0'; else txs_r <=3D txs_r; end if; ---------------------------------------- if (spi_clk_cnt_s((Gspi_clk_div/2)) =3D '1') then rxs_r <=3D rxs_r(rxs_r'high-1 downto 0) & miso_i; else rxs_r <=3D rxs_r; end if; ---------------------------------------- ssn_r <=3D '0'; spi_tx_done_o <=3D '0'; else FSMspi <=3D S3_END; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D rxs_r; ssn_r <=3D '0'; spi_tx_done_o <=3D '0'; end if; when S3_END =3D> if (spi_clk_cnt_s(0) =3D '1') then FSMspi <=3D S4_CSHI; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '1'; txs_r <=3D txs_r; rxs_r <=3D rxs_r; ssn_r <=3D '1'; spi_tx_done_o <=3D '0'; else FSMspi <=3D S3_END; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D txs_r; rxs_r <=3D rxs_r; ssn_r <=3D '0'; spi_tx_done_o <=3D '0'; end if; when S4_CSHI =3D> if (spi_clk_cnt_s(0) =3D '1') then FSMspi <=3D S0_IDLE; spi_clk_rstn_r <=3D '0'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D (others =3D> '0'); ssn_r <=3D '1'; spi_tx_done_o <=3D '1'; else FSMspi <=3D S4_CSHI; spi_clk_rstn_r <=3D '1'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D (others =3D> '0'); ssn_r <=3D '1'; spi_tx_done_o <=3D '0'; end if; when others =3D> FSMspi <=3D S0_IDLE; spi_clk_rstn_r <=3D '0'; spi_cyc_cnt_r <=3D 0; sck_r <=3D '0' xor cpol_i; tx_pop_r <=3D '0'; rx_push_r <=3D '0'; txs_r <=3D (others =3D> '0'); rxs_r <=3D (others =3D> '0'); ssn_r <=3D '1'; spi_tx_done_o <=3D '0'; end case; end if; end process prcs_FSMspi; --------------------------------------------------------------------------= ---------------------------------------------- mosi_o <=3D txs_r(txs_r'high) when (FSMspi =3D S2_CLK) else 'Z'; -- tri= state mosi_o when not driving spi_tx_empty_o <=3D tx_empty_s; sck_o <=3D sck_r; ssn_o <=3D ssn_r; --------------------------------------------------------------------------= ------ i_tx_fifo : SPI_Fifo generic map( Gram_type =3D> Gram_pref, Gdepth =3D> Gfifo_depth, Gdwidth =3D> Gdwidth ) port map( arstn =3D> arstn, clk =3D> clk, fifo_rst =3D> spi_rst_r, clken =3D> clken, push_i =3D> spi_wr_i, data_i =3D> spi_tx_data_i, full_o =3D> spi_tx_full_o, ovf_o =3D> spi_tx_ovf_o, pop_i =3D> tx_pop_r, data_o =3D> tx_data_s, empty_o =3D> tx_empty_s, unf_o =3D> spi_tx_unf_o ); ---------------------------------------- i_rx_fifo : SPI_Fifo generic map( Gram_type =3D> Gram_pref, Gdepth =3D> Gfifo_depth, Gdwidth =3D> Gdwidth ) port map( arstn =3D> arstn, clk =3D> clk, fifo_rst =3D> spi_rst_r, clken =3D> clken, push_i =3D> rx_push_r, data_i =3D> rxs_r, full_o =3D> spi_rx_full_o, ovf_o =3D> spi_rx_ovf_o, pop_i =3D> spi_rd_i, data_o =3D> spi_rx_data_o, empty_o =3D> spi_rx_empty_o, unf_o =3D> spi_rx_unf_o ); --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- end architecture rtl; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- -- component SPI_Master -- generic( -- Gram_pref : string; -- fifo ram type -- Gfifo_depth : positive; -- fifo length =3D 2**Gdepth -- Gdwidth : positive; -- fifo data width -- Gspi_clk_div : positive -- spi clock divider, >=3D2 and an even numbe= r -- ); -- port( -- arstn : in std_logic; -- clk : in std_logic; -- clken : in std_logic; -- spi_rst_i : in std_logic; -- reset the spi logic -- cpol_i : in std_logic; -- spi bus clock polarity "Freescale S= emiconductor, Inc." SPI Block Guide V4 S12SPIV4.pdf -- cpha_i : in std_logic; -- spi bus clock phase "Freescale Semi= conductor, Inc." SPI Block Guide V4 S12SPIV4.pdf -- spi_wr_i : in std_logic; -- write strobe -- spi_tx_data_i : in std_logic_vector(Gdwidth-1 downto 0); -- write data -- spi_tx_empty_o : out std_logic; -- write empty, ready to accept= data -- spi_tx_full_o : out std_logic; -- write full, will not accept n= ew data -- spi_tx_ovf_o : out std_logic; -- write overflowed -- spi_tx_unf_o : out std_logic; -- write underflowed -- spi_tx_done_o : out std_logic; -- write finished xmitting last = word -- spi_rd_i : in std_logic; -- read strobe -- spi_rx_data_o : out std_logic_vector(Gdwidth-1 downto 0); -- read data -- spi_rx_empty_o : out std_logic; -- read empty -- spi_rx_full_o : out std_logic; -- read full -- spi_rx_ovf_o : out std_logic; -- read overflow -- spi_rx_unf_o : out std_logic; -- read underflow -- sck_o : out std_logic; -- spi bus clock -- ssn_o : out std_logic; -- spi bus slave select, active low -- mosi_o : out std_logic; -- spi bus master out, slave in, tris= tate when inactive -- miso_i : in std_logic -- spi bus master in, slave out -- ); -- end component SPI_Master; -- i_ : SPI_Master -- generic map( -- Gram_pref =3D> , -- Gfifo_depth =3D> , -- Gdwidth =3D> , -- Gspi_clk_div =3D> -- ) -- port map( -- arstn =3D> , -- clk =3D> , -- clken =3D> , -- spi_rst_i =3D> , -- cpol_i =3D> , -- cpha_i =3D> , -- spi_wr_i =3D> , -- spi_tx_data_i =3D> , -- spi_tx_empty_o =3D> , -- spi_tx_full_o =3D> , -- spi_tx_ovf_o =3D> , -- spi_tx_unf_o =3D> , -- spi_tx_done_o =3D> , -- spi_rd_i =3D> , -- spi_rx_data_o =3D> , -- spi_rx_empty_o =3D> , -- spi_rx_full_o =3D> , -- spi_rx_ovf_o =3D> , -- spi_rx_unf_o =3D> , -- sck_o =3D> , -- ssn_o =3D> , -- mosi_o =3D> , -- miso_i =3D> -- ); ---------------------------------------------------------------------------= ---------------------------------------------------------------------------= ---------- -- File : SPI_Fifo.vhd -- Author : David Greig (email : dgreig@ieee.org) -- Revision : -- Description : Synchronous fifo, single shared clock domain ---------------------------------------------------------------------------= --------------------------------------------- -- Notes : --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- entity SPI_Fifo is generic( Gram_type : string; -- fifo ram type Gdepth : positive; -- fifo length =3D 2**Gdepth Gdwidth : positive -- fifo data width ); port( arstn : in std_logic; clken : in std_logic; clk : in std_logic; fifo_rst : in std_logic; -- reset the fifo pointer to the start push_i : in std_logic; -- push data in to fifo data_i : in std_logic_vector(Gdwidth - 1 downto 0); -- push data in full_o : out std_logic; -- push fifo full ovf_o : out std_logic; -- push fifo overflow pop_i : in std_logic; -- pop data out of fifo data_o : out std_logic_vector(Gdwidth - 1 downto 0); -- pop data out empty_o : out std_logic; -- pop fifo empty unf_o : out std_logic -- pop fifo underflow ); end entity SPI_Fifo; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- architecture rtl of SPI_Fifo is ---------------------------------------------------------------------------= --------------------------------------------- attribute ramstyle : string; -- "logic" "M512" "M4K" "M9K" "M144K" "MLAB" = "M-RAM" "no_rw_check" --------------------------------------------------------------------------= ---------------------------------------------- type t_fifo is array ((2**Gdepth-1) downto 0) of std_logic_vector((Gdwidth= -1) downto 0); signal fifo : t_fifo :=3D (others =3D> (others =3D> '0')); attribute rams= tyle of fifo : signal is Gram_type; signal wptr_r : std_logic_vector(Gdepth-1 downto 0); signal rptr_r : std_logic_vector(Gdepth-1 downto 0); signal full_r : boolean :=3D false; signal empty_r : boolean :=3D true; signal ovf_r : std_logic; signal unf_r : std_logic; ---------------------------------------------------------------------------= --------------------------------------------- begin ---------------------------------------------------------------------------= --------------------------------------------- prcs_cntl : process(arstn, clken, clk) begin if (arstn =3D '0') then wptr_r <=3D (others =3D> '0'); rptr_r <=3D (others =3D> '0'); full_r <=3D false; empty_r <=3D true; ovf_r <=3D '0'; unf_r <=3D '0'; elsif (clken =3D '0') then null; elsif (rising_edge(clk)) then if ((push_i =3D '1') and not(full_r)) then -- load fifo iff space avail= able wptr_r <=3D std_logic_vector(unsigned(wptr_r) + 1); end if; ---------------------------------------- if (pop_i =3D '1') then -- if fifo full_r then push into the last= available row full_r <=3D false; elsif ((push_i =3D '1') and (unsigned(wptr_r) =3D t_fifo'high)) then full_r <=3D true; end if; ---------------------------------------- if (pop_i =3D '1') then -- indicate overflow if we try to write t= o a full_r fifo ovf_r <=3D '0'; elsif (push_i =3D '1' and full_r) then ovf_r <=3D '1'; end if; ---------------------------------------- if ((pop_i =3D '1') and not(empty_r)) then -- only take data from the f= ifo if its available rptr_r <=3D std_logic_vector(unsigned(rptr_r) + 1); end if; ---------------------------------------- if (push_i =3D '1') then -- fifo is empty_r when we pop into the l= ast occupied slot empty_r <=3D false; elsif ((pop_i =3D '1') and ((unsigned(wptr_r) - unsigned(rptr_r)) =3D 1= )) then empty_r <=3D true; end if; ---------------------------------------- if (push_i =3D '1') then -- indicate underflow if we try and read = from an empty_r fifo unf_r <=3D '0'; elsif ((pop_i =3D '1') and (empty_r)) then unf_r <=3D '1'; end if; ---------------------------------------- if (fifo_rst =3D '1') then -- finally, synchronously reset everythi= ng if requested wptr_r <=3D (others =3D> '0'); rptr_r <=3D (others =3D> '0'); full_r <=3D false; empty_r <=3D true; ovf_r <=3D '0'; unf_r <=3D '0'; end if; end if; end process prcs_cntl; --------------------------------------------------------------------------= ------ prcs_ram : process (arstn, clken, clk) begin if (arstn =3D '0') then fifo <=3D (others =3D> (others =3D> '0')); data_o <=3D (others =3D> '0'); elsif (clken =3D '0') then null; elsif (rising_edge(clk)) then if ((push_i =3D '1') and not(full_r)) then -- only put data into the fi= fo if space is available fifo(to_integer(unsigned(wptr_r))) <=3D data_i; end if; data_o <=3D fifo(to_integer(unsigned(rptr_r))); end if; end process prcs_ram; --------------------------------------------------------------------------= ---------------------------------------------------------------------------= ----------- full_o <=3D '1' when full_r else '0'; empty_o <=3D '1' when empty_r else '0'; ovf_o <=3D ovf_r; unf_o <=3D unf_r; ---------------------------------------------------------------------------= --------------------------------------------- end architecture rtl; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- -- component SPI_Fifo -- generic( -- Gram_type : string; -- fifo ram type -- Gdepth : positive; -- fifo length =3D 2**Gdepth -- Gdwidth : positive -- fifo data width -- ); -- port( -- arstn : in std_logic; -- clken : in std_logic; -- clk : in std_logic; -- fifo_rst : in std_logic; -- reset the fifo pointer to the start -- push_i : in std_logic; -- push data in to fifo -- data_i : in std_logic_vector(Gdwidth - 1 downto 0); -- push data in -- full_o : out std_logic; -- push fifo full -- ovf_o : out std_logic; -- push fifo overflow -- pop_i : in std_logic; -- pop data out of fifo -- data_o : out std_logic_vector(Gdwidth - 1 downto 0); -- pop data out -- empty_o : out std_logic; -- pop fifo empty -- unf_o : out std_logic -- pop fifo underflow -- ); -- end component SPI_Fifo; -- i_ : SPI_Fifo -- generic map( -- Gram_type =3D> , -- Gdepth =3D> , -- Gdwidth =3D> -- ) -- port map( -- arstn =3D> , -- clk =3D> , -- fifo_rst =3D> , -- clken =3D> , -- push_i =3D> , -- data_i =3D> , -- full_o =3D> , -- ovf_o =3D> , -- pop_i =3D> , -- data_o =3D> , -- empty_o =3D> , -- unf_o =3D> -- ); ---------------------------------------------------------------------------= ---------------------------------------------------------------------------= ---------- -- File : Cnt_Ring_Rst.vhd -- Author : David Greig (email : dgreig@ieee.org) -- Revision : -- Description : Self correcting ring counter ---------------------------------------------------------------------------= -------------------------------------------- -- Notes : arstn and clken_i must meet required setup and hold requirements= of the register --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- library IEEE; use IEEE.std_logic_1164.all; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- entity Cnt_Ring_Rst is generic( Glen : positive ); port( arstn : in std_logic; clk : in std_logic; clken : in std_logic; cnt_rstn_i : in std_logic; q_o : out std_logic_vector(Glen - 1 downto 0) ); end entity Cnt_Ring_Rst; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- architecture rtl of Cnt_Ring_Rst is --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- signal cnt_ring_r : std_logic_vector(Glen - 1 downto 0); signal cnt_ring_next_s : std_logic_vector(Glen - 1 downto 0); signal set_s : std_logic; alias cnt_ring_high_s : std_logic_vector(Glen - 2 downto 0) is cnt_ring_r(= Glen - 1 downto 1); constant Ccnt_ringval_lo: std_logic_vector(Glen - 2 downto 0) :=3D (others= =3D> '0'); constant Ccnt_ringval : std_logic_vector(Glen - 1 downto 0) :=3D '1' & Ccn= t_ringval_lo; ---------------------------------------------------------------------------= --------------------------------------------- begin ---------------------------------------------------------------------------= --------------------------------------------- prcs_cnt_ring_r : process(arstn, clken, cnt_rstn_i, clk) begin if ((arstn =3D '0') or (cnt_rstn_i =3D '0')) then cnt_ring_r <=3D (others =3D> '0'); elsif (clken =3D '0') then null; elsif rising_edge(clk) then cnt_ring_r <=3D cnt_ring_next_s; end if; end process prcs_cnt_ring_r; --------------------------------------------------------------------------= ------ set_s <=3D '0' when ((arstn =3D '0') or (cnt_rstn_i =3D '0')) else '1' when (cnt_ring_high_s =3D (cnt_ring_high_s'range =3D> '0')) else '0'; cnt_ring_next_s <=3D (others =3D> '0') when ((arstn =3D '0') or (cnt= _rstn_i =3D '0')) else set_s & cnt_ring_r(Glen - 1 downto 1) when (cnt_rstn_i =3D '1') = else Ccnt_ringval; --------------------------------------------------------------------------= ---------------------------------------------- q_o <=3D cnt_ring_r; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- end architecture rtl; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- -- component Cnt_Ring_Rst -- generic( -- Glen : positive -- ); -- port( -- arstn : in std_logic; -- clk : in std_logic; -- clken : in std_logic; -- cnt_rstn_i : in std_logic; -- q_o : out std_logic_vector(Glen - 1 downto 0) -- ); -- end component Cnt_Ring_Rst; -- i_ : Cnt_Ring_Rst -- generic map( -- Glen =3D> -- ) -- port map( -- arstn =3D> , -- clk =3D> , -- clken =3D> , -- cnt_rstn_i =3D> , -- q_o =3D> -- ); ---------------------------------------------------------------------------= ---------------------------------------------------------------------------= ---------- -- File : tb_spi_slave.vhd -- Author : David Greig (email : dgreig@ieee.org) -- Revision : -- Description : testbench for spi master ---------------------------------------------------------------------------= --------------------------------------------- -- Notes : --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; library STD; use STD.textio.all; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- entity tb_spi_master is end entity tb_spi_master; --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~-- architecture behavioural of tb_spi_master is ---------------------------------------------------------------------------= --------------------------------------------- constant CLK_PERIOD : time :=3D 6.25 ns; constant Cram_pref : string :=3D "logic"; constant Cfifo_depth : natural :=3D 4; constant Cdwidth : natural :=3D 16; constant Cspi_clk_div : natural :=3D 4; signal arstn : std_logic :=3D '0'; signal clk : std_logic :=3D '0'; signal spi_arst_i : std_logic :=3D '0'; signal clken : std_logic :=3D '1'; signal cpol_i : std_logic :=3D '0'; signal cpha_i : std_logic :=3D '0'; signal spi_wr_i : std_logic :=3D '0'; signal spi_tx_data_i : std_logic_vector(Cdwidth-1 downto 0) :=3D (others = =3D> '0'); signal spi_tx_empty_o : std_logic; signal spi_tx_full_o : std_logic; signal spi_tx_ovf_o : std_logic; signal spi_tx_unf_o : std_logic; signal spi_tx_done_o : std_logic; signal spi_rd_i : std_logic :=3D '0'; signal spi_rx_data_o : std_logic_vector(Cdwidth-1 downto 0); signal spi_rx_empty_o : std_logic; signal spi_rx_full_o : std_logic; signal spi_rx_ovf_o : std_logic; signal spi_rx_unf_o : std_logic; signal sck_o : std_logic; signal ssn_o : std_logic; signal mosi_o : std_logic; signal miso_i : std_logic :=3D 'Z'; --------------------------------------------------------------------------= ------ component wrapper_SPI_Master port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic; cpol_i : in std_logic; cpha_i : in std_logic; spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(16-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic; spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(16-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic; sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end component wrapper_SPI_Master; --------------------------------------------------------------------------= ------ file tb_in : text open write_mode is "tb_in.txt"; file tb_out : text open write_mode is "tb_out.txt"; ---------------------------------------------------------------------------= --------------------------------------------- begin ---------------------------------------------------------------------------= --------------------------------------------- arstn <=3D '1' after CLK_PERIOD; ---------------------------------------- prcs_clkgen : process begin clk <=3D '1' after CLK_PERIOD/2, '0' after CLK_PERIOD; wait for CLK_PERIOD; end process prcs_clkgen; --------------------------------------------------------------------------= ------ prcs_tx_rx_loopback : process begin wait until falling_edge(ssn_o); wait for CLK_PERIOD*Cspi_clk_div; lp_miso_update : for idx in 0 to Cdwidth-1 loop wait for CLK_PERIOD*Cspi_clk_div*0.1; miso_i <=3D mosi_o; wait for CLK_PERIOD*Cspi_clk_div*0.9; end loop lp_miso_update; miso_i <=3D 'Z'; end process prcs_tx_rx_loopback; --------------------------------------------------------------------------= ------ prcs_rx_dread : process variable rxindex : integer; variable rx_data : integer; variable in_line : line; begin wait until rising_edge(spi_rd_i); lp_spi_rdd : for idx in 2**Cfifo_depth downto 1 loop --read the spi wait until falling_edge(clk); rxindex :=3D idx; rx_data :=3D to_integer( unsigned(spi_rx_data_o) ); write(in_line, string'("time" & HT)); write(in_line, now); write(in_line, string'("" & HT)); write(in_line, rxindex); write(in_line, string'("" & HT)); write(in_line, rx_data); writeline(tb_in, in_line); end loop lp_spi_rdd; end process prcs_rx_dread; --------------------------------------------------------------------------= ------ prcs_rx_read : process procedure prcd_spi_wait is begin lp_wait_sck : for idx in 1 to Cspi_clk_div loop wait until rising_edge(clk); end loop lp_wait_sck; end procedure; procedure prcd_spi_read is begin spi_rd_i <=3D '1'; wait until falling_edge(clk); spi_rd_i <=3D '0'; end procedure prcd_spi_read; begin wait until rising_edge(spi_rx_full_o); prcd_spi_wait; prcd_spi_wait; wait until falling_edge(clk); lp_spi_rd : for idx in 2**Cfifo_depth downto 1 loop --read the spi prcd_spi_read; end loop lp_spi_rd; end process prcs_rx_read; --------------------------------------------------------------------------= ------ prcs_main_tx_stim : process variable txindex : integer; variable tx_data : integer; variable out_line : line; procedure prcd_spi_wait is begin lp_wait_sck : for idx in 1 to Cspi_clk_div loop wait until rising_edge(clk); end loop lp_wait_sck; end procedure; procedure prcd_spi_write is begin spi_wr_i <=3D '1'; wait until falling_edge(clk); spi_wr_i <=3D '0'; tx_data :=3D to_integer( unsigned(spi_tx_data_i) ); write(out_line, string'("time" & HT)); write(out_line, now); write(out_line, string'("" & HT)); write(out_line, txindex); write(out_line, string'("" & HT)); write(out_line, tx_data); writeline(tb_out, out_line); end procedure prcd_spi_write; begin wait until rising_edge(clk) and arstn=3D '1'; wait for CLK_PERIOD/2; wait for 90 ns; wait until falling_edge(clk); -- fill the tx fifo lp_spi_wr00 : for idx in 2**Cfifo_depth downto 1 loop --report integer'image(idx); txindex :=3D idx; spi_tx_data_i <=3D std_logic_vector( TO_UNSIGNED(idx+2**(Cdwidth-1), Cdw= idth ) ); prcd_spi_write; end loop lp_spi_wr00; lp_wait00 : for idx in (2**Cfifo_depth)*(Cdwidth+16) downto 0 loop prcd_spi_wait; end loop lp_wait00; cpol_i <=3D '1'; cpha_i <=3D '0'; prcd_spi_wait; wait until falling_edge(clk); lp_spi_wr10 : for idx in 2**Cfifo_depth downto 1 loop txindex :=3D idx; spi_tx_data_i <=3D std_logic_vector( TO_UNSIGNED(idx, Cdwidth) ); prcd_spi_write; end loop lp_spi_wr10; lp_wait10 : for idx in (2**Cfifo_depth)*(Cdwidth+16) downto 0 loop prcd_spi_wait; end loop lp_wait10; cpol_i <=3D '0'; cpha_i <=3D '1'; prcd_spi_wait; wait until falling_edge(clk); lp_spi_wr01 : for idx in 2**Cfifo_depth downto 1 loop txindex :=3D idx; spi_tx_data_i <=3D std_logic_vector( TO_UNSIGNED(idx, Cdwidth) ); prcd_spi_write; end loop lp_spi_wr01; lp_wait01 : for idx in (2**Cfifo_depth)*(Cdwidth+16) downto 0 loop prcd_spi_wait; end loop lp_wait01; cpol_i <=3D '1'; cpha_i <=3D '1'; prcd_spi_wait; wait until falling_edge(clk); lp_spi_wr11 : for idx in 2**Cfifo_depth downto 1 loop txindex :=3D idx; spi_tx_data_i <=3D std_logic_vector( TO_UNSIGNED(idx, Cdwidth) ); prcd_spi_write; end loop lp_spi_wr11; lp_wait11 : for idx in (2**Cfifo_depth)*(Cdwidth+16) downto 0 loop prcd_spi_wait; end loop lp_wait11; wait until falling_edge(clk); wait for 10 us; file_close(tb_in); file_close(tb_out); report "End of simulation, stopping modelsim with failure assert" severit= y failure; end process prcs_main_tx_stim; --------------------------------------------------------------------------= ---------------------------------------------- dut : wrapper_SPI_Master port map( arstn =3D> arstn, clk =3D> clk, spi_rst_i =3D> spi_arst_i, clken =3D> clken, cpol_i =3D> cpol_i, cpha_i =3D> cpha_i, spi_wr_i =3D> spi_wr_i, spi_tx_data_i =3D> spi_tx_data_i, spi_tx_empty_o =3D> spi_tx_empty_o, spi_tx_full_o =3D> spi_tx_full_o, spi_tx_ovf_o =3D> spi_tx_ovf_o, spi_tx_unf_o =3D> spi_tx_unf_o, spi_tx_done_o =3D> spi_tx_done_o, spi_rd_i =3D> spi_rd_i, spi_rx_data_o =3D> spi_rx_data_o, spi_rx_empty_o =3D> spi_rx_empty_o, spi_rx_full_o =3D> spi_rx_full_o, spi_rx_ovf_o =3D> spi_rx_ovf_o, spi_rx_unf_o =3D> spi_rx_unf_o, sck_o =3D> sck_o, ssn_o =3D> ssn_o, mosi_o =3D> mosi_o, miso_i =3D> miso_i ); --=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D-- end architecture behavioural;
Reply by ●October 18, 20142014-10-18
You have a CDC (clock-domain-crossing) situation going from a fast clock domain to a slow clock domain. Some others have already mentioned solutions: On Saturday, October 18, 2014 3:53:31 AM UTC-4, nor...@googlegroups.com wrote:> I'm wondering what the correct way to handle the following situation > > is. Sorry this is a bit long winded. BTW, it's not homework, all that > > was 40+ years ago. > > > > > > I have two clocks, clk which is the FPGA clock rate, and sclk which I > > create using a simple divide by n counter. Typically, sclk is 1024 > > times slower than clk. > > > > An event occurs that sets a reg, DR, for one clk cycle. > > > > There is a register, calcreg [7:0] which is to be incremented slowly, > > but reset to zero on DR. > > > > There are two sections, one triggered by clk and one by sclk, ie: > > > > // Fast section > > always @ (posedge clk) > > begin > > .... > > end > > > > // Slow section > > always @ (posedge sclk) > > begin > > if (DR) calcreg <= 8'h0 ; // Reset calcreg on DR > > else calcreg <= calcreg + 1 ; // Else increment > > end > > > > The problem of course is that the on state of DR will almost always be > > missed, it will only appear if it happens to coincide with a sclk edge > > (1 / 1024). So the above doesn't work. > > > > So I tried modifying the clk section as follows: > > > > always @ (posedge clk) > > begin > > .... > > if (DR) calcreg <= 8'h0 ; > > end > > > > This threw up build errors, > > > > Error (10028): Can't resolve multiple constant drivers for net > > "FlashCtr[3]" at tick.v(43) > > > > I think I see the reason, it's like trying to wire two gate outputs to > > the same point, something that's obviously verboten with active drive > > hardware. > > > > > > If someone could help with the following specific questions it would > > help a lot..... > > > > Is using the two clocks simply bad practice, ie. should everything be > > done in a single always block at clk rate? > > > > Is there a standard way to latch the DR signal when it occurs on the > > fast clock, so that it will be there on the next transition of sclk, > > which must then clear the DR latch? I've tried this, and come up with > > the same build error with the latch.
Reply by ●October 18, 20142014-10-18
On Sat, 18 Oct 2014 10:53:42 -0400, Gabor wrote:> On 10/18/2014 3:53 AM, "Bruce Varley" wrote: >> I'm wondering what the correct way to handle the following situation >> is. Sorry this is a bit long winded. BTW, it's not homework, all that >> was 40+ years ago. >> >> >> I have two clocks, clk which is the FPGA clock rate, and sclk which I >> create using a simple divide by n counter. Typically, sclk is 1024 >> times slower than clk. >> >> An event occurs that sets a reg, DR, for one clk cycle. >> >> There is a register, calcreg [7:0] which is to be incremented slowly, >> but reset to zero on DR. >> >> There are two sections, one triggered by clk and one by sclk, ie: >> >> // Fast section always @ (posedge clk) >> begin .... >> end >> >> // Slow section always @ (posedge sclk) >> begin if (DR) calcreg <= 8'h0 ; // Reset calcreg on DRelse>> calcreg <= calcreg + 1 ; // Else increment end >> >> The problem of course is that the on state of DR will almost always be >> missed, it will only appear if it happens to coincide with a sclk edge >> (1 / 1024). So the above doesn't work. >> >> So I tried modifying the clk section as follows: >> >> always @ (posedge clk) >> begin .... >> if (DR) calcreg <= 8'h0 ; >> end >> >> This threw up build errors, >> >> Error (10028): Can't resolve multiple constant drivers for net >> "FlashCtr[3]" at tick.v(43) >> >> I think I see the reason, it's like trying to wire two gate outputs to >> the same point, something that's obviously verboten with active drive >> hardware. >> >> >> If someone could help with the following specific questions it would >> help a lot..... >> >> Is using the two clocks simply bad practice, ie. should everything be >> done in a single always block at clk rate? >> >> Is there a standard way to latch the DR signal when it occurs on the >> fast clock, so that it will be there on the next transition of sclk, >> which must then clear the DR latch? I've tried this, and come up with >> the same build error with the latch. >> >> > If you're really just dividing one clock to make another, then you're > probably better off using a single clock and generating a count enable > for your slow process. On the other hand your problem of using a fast > signal to reset a slow process is also applicable to situations where > the two clocks are not related and are both necessary for the design. In > that case I would normally have an intermediate variable in the fast > clock domain that gets set by DR and cleared by a signal returned from > the slow process. Something like: > > reg DR_hold = 0; > reg DR_seen = 0; > always @ (posedge clk) > begin > if (DR) DR_hold <= 1; > else if (DR_resync) DR_hold <= 0; > end > > always @ (posedge sclk) > begin > DR_resync <= DR_hold; > end > > Note that if you use DR_resync as the reset term, it will cause > additional latency from DR to the reset of the counter. > You could use DR_hold instead, but then the problem is if the two clocks > are really unrelated you could miss a reset if DR_hold asserts very near > the rising edge of sclk and DR_resync catches the event but the counter > (or some of its bits) does not.+1. Using the DR_resync (who looks at 'reg' declarations, anyway) should work even if sclk isn't generated from clk. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com
Reply by ●October 18, 20142014-10-18
You have a CDC (clock-domain-crossing) situation going from a fast to slow = domain. Are you sure those clocks are synchronous?Some solutions have alrea= dy been mentioned: 1) Use a single clock domain for everything and just capture the event in t= he fast clock domain and clear it when you enable the slow domain (count=3D= =3D1024). This will consume more power as you are using the same clock for = all logic but you have a fully synchronous design (easier for timing).=20 2) Use handshake to pass the signal across the CDC boundary but be sure to = double-register signals to avoid metastability (asynchronous clock crossing= ). i.e. Gabor's code with synchronizing flops. It really depends on the relationship between the clocks in your design. St= aying synchronous keeps things a lot simpler. -Ganesh On Saturday, October 18, 2014 3:53:31 AM UTC-4, nor...@googlegroups.com wro= te:> I'm wondering what the correct way to handle the following situation >=20 > is. Sorry this is a bit long winded. BTW, it's not homework, all that >=20 > was 40+ years ago. >=20 >=20 >=20 >=20 >=20 > I have two clocks, clk which is the FPGA clock rate, and sclk which I >=20 > create using a simple divide by n counter. Typically, sclk is 1024 >=20 > times slower than clk.=20 >=20 >=20 >=20 > An event occurs that sets a reg, DR, for one clk cycle.=20 >=20 >=20 >=20 > There is a register, calcreg [7:0] which is to be incremented slowly, >=20 > but reset to zero on DR. >=20 >=20 >=20 > There are two sections, one triggered by clk and one by sclk, ie: >=20 >=20 >=20 > // Fast section >=20 > always @ (posedge clk) >=20 > begin >=20 > .... >=20 > end >=20 >=20 >=20 > // Slow section >=20 > always @ (posedge sclk) >=20 > begin >=20 > if (DR) calcreg <=3D 8'h0 ; // Reset calcreg on DR=20 >=20 > else calcreg <=3D calcreg + 1 ; // Else increment >=20 > end >=20 >=20 >=20 > The problem of course is that the on state of DR will almost always be >=20 > missed, it will only appear if it happens to coincide with a sclk edge >=20 > (1 / 1024). So the above doesn't work. >=20 >=20 >=20 > So I tried modifying the clk section as follows: >=20 > =20 >=20 > always @ (posedge clk) >=20 > begin >=20 > .... >=20 > if (DR) calcreg <=3D 8'h0 ; =20 >=20 > end >=20 >=20 >=20 > This threw up build errors,=20 >=20 >=20 >=20 > Error (10028): Can't resolve multiple constant drivers for net >=20 > "FlashCtr[3]" at tick.v(43) >=20 >=20 >=20 > I think I see the reason, it's like trying to wire two gate outputs to >=20 > the same point, something that's obviously verboten with active drive >=20 > hardware.=20 >=20 >=20 >=20 >=20 >=20 > If someone could help with the following specific questions it would >=20 > help a lot..... >=20 >=20 >=20 > Is using the two clocks simply bad practice, ie. should everything be >=20 > done in a single always block at clk rate? >=20 >=20 >=20 > Is there a standard way to latch the DR signal when it occurs on the >=20 > fast clock, so that it will be there on the next transition of sclk, >=20 > which must then clear the DR latch? I've tried this, and come up with >=20 > the same build error with the latch.
Reply by ●October 18, 20142014-10-18
Bruce Varley:> I'm wondering what the correct way to handle the following situation is. > Sorry this is a bit long winded. BTW, it's not homework, all that was > 40+ years ago.A good question, and it sounds like you're already analysing the problems correctly. In terms of electronic circuit complexity (however), the problem you describe scales down to what single design primitives of the hardware deliver. So it'll be best to start with taking a look at what kind of design primitives are supported by the hardware platform (so in case of an FPGA, the interesting information would be about which "slice"-FlipFlop-Types are available). To me it seems like at least all Xilinx FPGA support both, synchroneous and asychroneous (re)set for clocked data paths. If I got your pronlem description correcty, a simple solution would be to use async reset FlipFlops for calcreg: always @(posedge sclk or posedge DR) begin if (DR) calcreg <= n'b0 else calcreg <= calcreg + n'd1; end Gruss Jan Bruns






