M
M. Norton
Guest
Okay, this is sort of a spin-off to my previous question about
bidirectionals and their behavior. This is a bit of a separate topic
though and I don't want to get them confused.
Essentially I'm looking for a semantic template for what I'm trying to
do, but I don't have a lot of experience with non-RTL construction.
Usually with RTL there's a fast clock I can use to synchronize
everything nicely. However, with this DAC, it does not have an
interior clock, and is completely driven by a SCLK input that is only
occasionally active, during
data transfers.
So I thought I'd try to model this device the way it behaves, but the
lack of a consistent clock makes things decidedly tricky (not to
mention the bidirectional port.)
Here's how I compartmentalized the behavior. I identified four main
states: idle, rx_cmd, rx_data, tx_data. Now, for each of those states
there are a number of similar behaviors that happen that I thought
would be good to break into procedures. rx_byte, tx_byte, rx_ack,
tx_ack, and wait_for_stop.
So, here's kind of how I thought the process might look. However, I'm
not sure it's going to work, so I thought I'd ask and see what folks
thought. It's not all filled in yet, but here's the basic structure.
After the code I'll ask the questions.
--
-- Reset behavior
--
reset <= '1', '0' after POR_DURATION;
DAC_FSM : process
procedure rx_byte(clk : in std_logic,
sda : in std_logic,
byte : out std_logic) is
begin
end procedure receive_byte;
procedure tx_byte(clk : in std_logic,
byte : in std_logic,
sda : out std_logic) is
begin
end procedure tx_byte;
procedure tx_ack(clk : in std_logic,
sda : out std_logic) is
end procedure tx_ack;
procedure rx_ack(clk : in std_logic,
sda : in std_logic,
ok : out boolean) is
end function rx_ack;
procedure
begin
--
-- Define behavior under reset
--
addr_reg <= (others => '0');
rw_reg <= (others => '0');
pd_reg <= (others => '0');
control_reg <= (others => '0');
sda <= 'Z';
dac_state <= IDLE;
wait until falling_edge(reset);
case dac_state is
when IDLE =>
sda <= 'Z';
wait until falling_edge(sda) and sclk = '1';
dac_state <= RX_CMD;
when RX_CMD =>
rx_byte(sclk, sda, byte);
tx_ack(sclk, sda);
if (byte(0) = '1') then
dac_state <= RX_DATA;
else
dac_state <= TX_DATA;
end if;
when RX_DATA =>
when TX_DATA =>
when others =>
null;
end case
end process;
So, some questions
1) If I suspend the process inside a procedure, when the process re-
enters, will it jump to the procedure the way it's supposed to? I
think this is true, but I need to check.
2) In that IDLE state, I select the next state based on a bit. From
what I can tell then the flow will move to end case, and exit the
process and.... a miracle happens? How can I get it to re-enter the
process to pick up on the next state? I don't have a clock to depend
on here, it's entirely based on some level transitions, so I can't put
in a "wait until rising_edge(clk)" for re-entry.
3) If it did re-enter after the idle... will it try to run those
default assignments and wait for reset again? That could be very bad.
4) Addressed in that other thread, but for inout port sda, assigning
it to Z and also checking to see if it's a value in the same region is
legal? Inouts are starting to drive me crazy and wish for some simple
RTL to design.
I think that's the main points of interest. I love the richness of
the language, but when I leave my little shelter of synthesizable
code, I feel a bit adrift at sea ;-).
Best regards,
Mark Norton
bidirectionals and their behavior. This is a bit of a separate topic
though and I don't want to get them confused.
Essentially I'm looking for a semantic template for what I'm trying to
do, but I don't have a lot of experience with non-RTL construction.
Usually with RTL there's a fast clock I can use to synchronize
everything nicely. However, with this DAC, it does not have an
interior clock, and is completely driven by a SCLK input that is only
occasionally active, during
data transfers.
So I thought I'd try to model this device the way it behaves, but the
lack of a consistent clock makes things decidedly tricky (not to
mention the bidirectional port.)
Here's how I compartmentalized the behavior. I identified four main
states: idle, rx_cmd, rx_data, tx_data. Now, for each of those states
there are a number of similar behaviors that happen that I thought
would be good to break into procedures. rx_byte, tx_byte, rx_ack,
tx_ack, and wait_for_stop.
So, here's kind of how I thought the process might look. However, I'm
not sure it's going to work, so I thought I'd ask and see what folks
thought. It's not all filled in yet, but here's the basic structure.
After the code I'll ask the questions.
--
-- Reset behavior
--
reset <= '1', '0' after POR_DURATION;
DAC_FSM : process
procedure rx_byte(clk : in std_logic,
sda : in std_logic,
byte : out std_logic) is
begin
end procedure receive_byte;
procedure tx_byte(clk : in std_logic,
byte : in std_logic,
sda : out std_logic) is
begin
end procedure tx_byte;
procedure tx_ack(clk : in std_logic,
sda : out std_logic) is
end procedure tx_ack;
procedure rx_ack(clk : in std_logic,
sda : in std_logic,
ok : out boolean) is
end function rx_ack;
procedure
begin
--
-- Define behavior under reset
--
addr_reg <= (others => '0');
rw_reg <= (others => '0');
pd_reg <= (others => '0');
control_reg <= (others => '0');
sda <= 'Z';
dac_state <= IDLE;
wait until falling_edge(reset);
case dac_state is
when IDLE =>
sda <= 'Z';
wait until falling_edge(sda) and sclk = '1';
dac_state <= RX_CMD;
when RX_CMD =>
rx_byte(sclk, sda, byte);
tx_ack(sclk, sda);
if (byte(0) = '1') then
dac_state <= RX_DATA;
else
dac_state <= TX_DATA;
end if;
when RX_DATA =>
when TX_DATA =>
when others =>
null;
end case
end process;
So, some questions
1) If I suspend the process inside a procedure, when the process re-
enters, will it jump to the procedure the way it's supposed to? I
think this is true, but I need to check.
2) In that IDLE state, I select the next state based on a bit. From
what I can tell then the flow will move to end case, and exit the
process and.... a miracle happens? How can I get it to re-enter the
process to pick up on the next state? I don't have a clock to depend
on here, it's entirely based on some level transitions, so I can't put
in a "wait until rising_edge(clk)" for re-entry.
3) If it did re-enter after the idle... will it try to run those
default assignments and wait for reset again? That could be very bad.
4) Addressed in that other thread, but for inout port sda, assigning
it to Z and also checking to see if it's a value in the same region is
legal? Inouts are starting to drive me crazy and wish for some simple
RTL to design.
I think that's the main points of interest. I love the richness of
the language, but when I leave my little shelter of synthesizable
code, I feel a bit adrift at sea ;-).
Best regards,
Mark Norton