I'm trying to remove bitbashing in my design and sending test signals from outside the DUT using a procedure. The format of the serialized message is a start bit of '0', the byte with MSB first, and a stop bit of '1'. The line idles at '1'. I think I'm having issue making use of datatypes to be passed between the procedure and the main process.
Here is my procedure (baudrate is a time constant for the period of the serial clock):
procedure send_midi_byte (
signal byte_in : in std_logic_vector;
signal midi_out : out std_logic) is
begin
midi_out <= '0';
wait for baudrate;
for i in 7 to 0 loop
midi_out <= byte_in(i);
wait for baudrate;
end loop;
midi_out <= '1';
wait for baudrate;
end send_midi_byte;
And here is how I call it to send a few bytes (byte_slv is an 8 element std_logic_vector):
byte_slv <= x"90";
send_midi_byte(byte_slv, midi_in_int);
I have tried a few different methods and this is the only one that doesn't give an error, but of course it won't work because of the nonblocking assignments in the procedure meaning my serial signal will just be '1' for the length of time specified in baudrate.
How can I write this procedure correctly?
I have tried a few different methods and this is the only one that doesn't give an error, but of course it won't work because of the nonblocking assignments in the procedure meaning my serial signal will just be '1' for the length of time specified in baudrate.
The premise of your assertion here is incorrect. The reason why the procedure call fails is the loop parameter specification provides a null range (the loop parameter is evaluated first, a loop statement executes 0 or more times).
How can I write this procedure correctly?
A Minimal, Complete, and Verifiable example with the fix included in procedure send_midi_byte
:
library ieee;
use ieee.std_logic_1164.all;
entity cmoc_cmoc is
end entity;
architecture mcve of cmoc_cmoc is
constant baudrate: time := 26.925 us; -- 38.400 baud
procedure send_midi_byte (
signal byte_in: in std_logic_vector;
signal midi_out: out std_logic
) is
alias in_byte: std_logic_vector (7 downto 0) is byte_in; -- ADDED
begin
midi_out <= '0';
wait for baudrate;
for i in in_byte'range loop -- WAS 7 to 0
midi_out <= in_byte(i); -- WAS byte_in(i);
wait for baudrate;
end loop;
midi_out <= '1';
wait for baudrate;
end procedure send_midi_byte;
signal some_byte: std_logic_vector (7 downto 0) := x"41";
signal midi_out: std_logic := '1';
type baud is (IDLE,START, BD0, BD1, BD2, BD3, BD4, BD5, BD6, BD7, STOP);
signal baud_cnt: baud;
begin
PROCEDURE_CALL:
process
begin
wait for baudrate; -- SHOW IDLE on midi_out;
send_midi_byte(some_byte, midi_out); -- added second parameter
wait;
end process;
BAUD_CTR:
process
begin
if baud_cnt = IDLE then
wait until midi_out = '0';
end if;
loop
baud_cnt <= baud'RIGHTOF(baud_cnt);
wait for 0 ns;
report "baud(" & baud'image(baud_cnt) &
") midi_out = " & std_ulogic'image(midi_out);
wait for baudrate;
if baud_cnt = STOP then
baud_cnt <= IDLE;
exit;
end if;
end loop;
wait;
end process;
end architecture;
Note the class of byte_in
isn't provided in the procedure declaration. For a subprogram parameter of mode in
the default class is constant
.
The MSB first order has been preserved to match your question text. (UARTs transmit the LSB first).
The BAUD_CTR
process is an embellishment to demonstrate transmitted baud order.
For a UART with an input byte given as MSB on the left and transmitting the LSB first either the alias range can be reversed or the loop parameter could use `REVERSE_RANGE.
The report statements:
ghdl -r cmoc_cmoc --wave=cmoc_cmoc.ghw
cmoc_cmoc.vhdl:45:13:@26925ns:(report note): baud(start) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@53850ns:(report note): baud(bd0) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@80775ns:(report note): baud(bd1) midi_out = '1'
cmoc_cmoc.vhdl:45:13:@107700ns:(report note): baud(bd2) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@134625ns:(report note): baud(bd3) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@161550ns:(report note): baud(bd4) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@188475ns:(report note): baud(bd5) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@215400ns:(report note): baud(bd6) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@242325ns:(report note): baud(bd7) midi_out = '1'
cmoc_cmoc.vhdl:45:13:@269250ns:(report note): baud(stop) midi_out = '1'
And a waveform showing baud_cnt
: