Encoder for bitstream audio format to SDIF VHDL - audio

I'm a newbie in VHDL programming, however I'm trying to achieve SDIF encoding from a dsd datastream coming off from an A-D conversion chip.
The dsd stream from the chip features two independent channels (L&R) data flow,
plus a bitclock line.
The SDIF-3 coding scheme states that the channel coding splits each original bit in a 2 'semi-bit' pattern at double the original bitclock rate.
For ex., if the original bit is 0 the pattern gives the original value+it's inverted, so 0-1, if the bit value of the source stream is 1, the pattern is '1-0', and so on...
I was thinking of using a double-edge triggering to do the frequency doubling of the output stream.
So at the rising edge, the encoder output gives the first semi-bit value, and on the falling edge, the encoder outputs the inverted semi-bit to complete the pattern.
Please see the image below on official coding scheme for this format.
I'm not sure if the code is correct, even if it is possible to do it that way.
Unfortunately I have lack of knowledge on how to simulate this.
Any help, suggestion, greatly appreciated.
My code below...
library ieee;
use ieee.std_logic_1164.all;
entity ENCODER1 is
PORT (
clk_in : in std_logic;
data_l : in std_logic;
data_r : in std_logic;
out_l : out std_logic;
out_r : out std_logic
);
end entity ENCODER1;
architecture rtl of ENCODER1 is
signal q0 : std_logic; --output left
signal q1 : std_logic; --output right
signal d0, d1,clk : std_logic ;
begin
p0: process (d0, d1, clk) is
begin
if (clk'EVENT and clk ='1') then --detect source data # rising edge
q0 <= d0;
q1 <= d1;
if (clk'EVENT and clk ='0') then
q0 <= not d0;
q1 <= not d1;
end if;
end if;
end process p0;
end architecture rtl;
sdif encoding

You can't synthesize two edge events.
One solution is to use a mux and select the mux input with your clock:
out <= d0 when clk else not d0;
As you always want to invert the signal you can also use the clock with an exor gate:
out <= d0 xor not clk;
Note that some FPGAs are notoriously bad at using the clock with logic. The clock has to be specially routed and that can increase the skew significantly.
If your signal goes directly to a output port the manufacturers recommended you use a special DDR I/O port. For Xilinx search for the ODDR I/O primitive of the relevant FPGA you are using. It has all the logic inside to do the work for you.

Related

Edge triggered flip flop behaving like a transparent latch when sensitivity list has two rising edges

Trying this on a Terasic DE10-Lite, programmed with Quartus Prime Lite Edition.
SW[0] is a switch. LEDR[0] is an LED. KEY[0] is a push button. The push button is active low.
I want to model a flip flop that stores SW[0] in register r0 and displays it in LEDR[0] when KEY[0] delivers a rising edge.
The following works as expected:
module flipfloptest (
input [9:0] SW,
input [1:0] KEY,
output [9:0] LEDR);
reg r0;
assign LEDR[0] = r0;
always #(posedge(~KEY[0]))
r0 <= SW[0];
endmodule
I now add another push button, KEY[1], to the sensitivity list with the intention that pushing either down will set the flip flop.
module flipfloptest (
input [9:0] SW,
input [1:0] KEY,
output [9:0] LEDR);
reg r0;
assign LEDR[0] = r0;
always #(posedge(~KEY[0]) or posedge(~KEY[1]))
r0 <= SW[0];
endmodule
This behaves like a latch (i.e. no longer edge triggered). LEDR[0] immediately reflects the state of SW[0] without the need to press either KEY[0] or KEY[1]. Pressing one or both does not affect behavior in any way.
Clearly, I don't understand the meaning of this sensitivity list. What is the correct interpretation?
More context: I can get the desired behavior using a clock and state machine as shown below. My question is why the sensitivity list isn't behaving intuitively.
module flipfloptest (
input MAX10_CLK1_50,
input [9:0] SW,
input [1:0] KEY,
output [9:0] LEDR);
reg [1:0] tic0, tic1;
reg r0;
assign LEDR[0] = r0;
always #(posedge MAX10_CLK1_50) begin
case (tic0)
0: tic0 = (~KEY[0])?1:0;
1: tic0 = (~KEY[0])?2:0;
2: tic0 = (~KEY[0])?2:0;
endcase
case (tic1)
0: tic1 = (~KEY[1])?1:0;
1: tic1 = (~KEY[1])?2:0;
2: tic1 = (~KEY[1])?2:0;
endcase
if (tic0==1 | tic1==1)
r0 <= SW[0];
end
endmodule
Synthesis tools only recognize certain Verilog coding patterns. Refer to synthesizable constructs. The documentation for your Quartus tool set should describe what coding styles are supported.
Your 1st and 3rd code examples adhere to the synthesizable coding style, whereas your 2nd example does not. You should look at the log files that your synthesis tools created: there should be messages in there warning you about unintended latches.
The code in your 2nd example is unusual. Perhaps your synthesis tool did not know what to do with it, and it just decided to give you a latch. Unfortunately for you, that is not how your code simulates.
This code:
always #(posedge(~KEY[0]) or posedge(~KEY[1]))
r0 <= SW[0];
can be simplified as:
always #(negedge KEY[0] or negedge KEY[1])
r0 <= SW[0];
r0 will be updated with SW[0] every time you get a negedge of either KEY[0] or KEY[1]. That does not behave like a latch. But, as I said, this code does not adhere to typical synthesis coding style.

How do I drive a signal from 2 sources in system verilog

I'm trying to write a RTL model in which I monitor independent clock sources. These clock sources can have variable frequency (range 5 to 50MHz)
Let us say clk1 and clk2. I'm trying to drive a signal 'toggle' which is set '1' at every posedge of clk1 and is set to '0' at every negedge of clk2. I'm having trouble realizing this model.
I tried using 1 flop triggered at the positive edge of clk1 with inputs of this flop tied to 'high' and another flip flop triggered at the negative edge of clk2 with input tied to 'low'. I sent these outputs to a mux, but I have trouble figuring out how to drive the select signal of this mux
Here is my code snippet :
always_ff #(posedge clk1 or rstb) begin
if(!rstb) begin
flop1_out <= 0;
end else begin
flop1_out <= 1;
end
end
always_ff #(negedge clk2) begin
flop2_out <= 0;
end
assign toggle = sel ? flop1 : flop2;
So, as of now nothing is driving sel and trying to figure this out is where I'm having trouble
If I try to drive the same signal (toggle) from 2 different clock sources, I get an error saying that multiple drivers found for signal toggle, which makes sense.
Please let me know if you have any suggestions
EDIT: fixed a typo and removed rstb from the sensitivity list for flop2
assign rstn = clk2;
always # (posedge clk1 or negedge rstn)
if (~rstn)
toggle = 1'b0;
else
toggle <= 1'b1;
note: depending on the clock frequency and insertion delay relationships this circuit may become metastable. if you can tolerate delay, add a synchronizer on the output. better yet, if you can tolerate distortion, add a reset synchronizer on clk2 to clk1mx, where clk1mx is synchronous to clock1 but x times faster.

Configure ModelSim simulation to display text

Can I make ModelSim simulation to display text (rather than a numeric value) on a signal? I have a couple of state-machine states say,
localparam S_IDLE = 2'b00;
localparam S_START = 2'b01;
localparam S_STOP = 2'b10;
Is there a way to display S_IDLE for example, on a signal rather than 00? Thanks.
One thing you can do that is should work across all simulators is to create a signal that holds an ascii string, and then change the radix of that signal to ascii in the simulation window:
reg [8*8-1:0] mytextsignal;
always#(state) begin
case(state)
S_IDLE : mytextsignal = " S_IDLE";
S_START: mytextsignal = " S_START";
S_STOP: mytextsignal = " S_STOP";
default: mytextsignal = " UNKNOWN";
endcase
end
It should show up as readable text in the waveform viewer.
In Modelsim you can add FSM using following steps:
use FSM recognition and FSM coverage options (+acc, +cover) during compile,
use the -fsmdebug and -coverage options on the vsim command line.
Check ModelSim User's Manual for more details. Notice that using View > FSM list you can check all FSMs detected by ModelSim and add it to a wave.

Why use this 2 DFF method every time a button press is involved?

I have been reading verilog code online and have noticed this in many of the code examples. Whenever an input is needed from a hardware source such as a button press, the input is copied to a flip flop and then AND'd with the invert of the input. I dont know if this made much sense but in code here it is:
input btn;
reg dff1, dff2;
wire db_tick;
always # (posedge clock) dff1 <= btn;
always # (posedge clock) dff2 <= dff1;
assign db_tick = ~dff1 & dff2;
And then db_tick is used as the button press.
In some cases this is also used as a rising edge detector, but cant a rising edge detector easily be implemented with always#(posedge signal)
It's called a monostable multivibrator or, specifically for digital circuits, a one-shot. The purpose of the circuit is to change an edge into a single cycle pulse.
When connected directly to a physical switch it can be a way to effect switch debouncing, but that's not really a good use for it. It's hard to say what the intent is in the code without more context.
This is providing edge detection synchronous to your clock domain. I do not see any debouncing happing here, it is quite common to also include 2 meta stability flip flops before the edge detection.
input a;
reg [2:0] a_meta;
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
a_meta <= 3'b0 ;
end
else begin
a_meta <= {a_meta[1:0], a};
end
end
// The following signals will be 1 clk wide, Clock must be faster than event rate.
// a[2] is the oldest data,
// if new data (a[1]) is high and old data low we have just seen a rising edge.
wire a_sync_posedge = ~a_meta[2] & a_meta[1];
wire a_sync_negedge = a_meta[2] & ~a_meta[1];
wire a_sync_anyedge = a_meta[2] ^ a_meta[1]; //XOR

How to generate serial signal from string?

How do I send data represented by a binary string (e.g. "01011101000100111", length is variable) to an std_logic signal given either fixed delay or clock signal? I want this for a testbench so I'd want to be able to arbitrarily change the binary string with as little hassle as possible, so I'm thinking of using generate.
I humbly present a fixed-delay version (it is testbench code after all...). I've checked this and it works, but I'm more comfortable in verilog so this code may no be the nicest VHDL ever...
--
-- Clocking out bitstream
--
library ieee;
use ieee.std_logic_1164.all;
entity stackoverflow_strings is
end stackoverflow_strings;
-- this is testbench code, so we can use "wait"s inside a "for" loop.
architecture rtl of stackoverflow_strings is
signal my_output : std_ulogic;
begin
shift_data : process is
constant my_bits : std_logic_vector := B"100101010000100010101";
begin
my_output <= '0';
wait for 10 ns;
for i in my_bits'range loop
my_output <= my_bits(i);
wait for 10 ns;
end loop;
wait;
end process shift_data;
end rtl;
To add to Marty's fine answer:
To make it clocked, change the wait for 10 ns;s to wait until rising_edge(clk);

Resources