Trying to verify Verilog/VHDL designs with formal methods and tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
11 KiB

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. use ieee.numeric_std.all;
  4. entity vai_reg is
  5. generic (
  6. Formal : boolean := true
  7. );
  8. port (
  9. Reset_n_i : in std_logic;
  10. Clk_i : in std_logic;
  11. -- req
  12. Din_i : in std_logic_vector(7 downto 0);
  13. DinValid_i : in std_logic;
  14. DinStart_i : in std_logic;
  15. DinStop_i : in std_logic;
  16. DinAccept_o : out std_logic;
  17. -- ack
  18. Dout_o : out std_logic_vector(7 downto 0);
  19. DoutValid_o : out std_logic;
  20. DoutStart_o : out std_logic;
  21. DoutStop_o : out std_logic;
  22. DoutAccept_i : in std_logic
  23. );
  24. end entity vai_reg;
  25. architecture rtl of vai_reg is
  26. constant C_READ : std_logic_vector(3 downto 0) := x"0";
  27. constant C_WRITE : std_logic_vector(3 downto 0) := x"1";
  28. type t_fsm_state is (IDLE, GET_HEADER, GET_DATA,
  29. SET_DATA, SEND_HEADER, SEND_DATA, SEND_FOOTER);
  30. signal s_fsm_state : t_fsm_state;
  31. type t_register is array(0 to 7) of std_logic_vector(7 downto 0);
  32. signal s_register : t_register;
  33. signal s_header : std_logic_vector(7 downto 0);
  34. signal s_data : std_logic_vector(7 downto 0);
  35. signal s_error : boolean;
  36. signal s_dout_accepted : boolean;
  37. alias a_addr : std_logic_vector(3 downto 0) is s_header(7 downto 4);
  38. begin
  39. s_dout_accepted <= (DoutValid_o and DoutAccept_i) = '1';
  40. process (Reset_n_i, Clk_i) is
  41. begin
  42. if (Reset_n_i = '0') then
  43. DinAccept_o <= '0';
  44. DoutStart_o <= '0';
  45. DoutStop_o <= '0';
  46. DoutValid_o <= '0';
  47. Dout_o <= (others => '0');
  48. s_header <= (others => '0');
  49. s_data <= (others => '0');
  50. s_register <= (others => (others => '0'));
  51. s_error <= false;
  52. s_fsm_state <= IDLE;
  53. elsif (rising_edge(Clk_i)) then
  54. case s_fsm_state is
  55. when IDLE =>
  56. DinAccept_o <= '0';
  57. DoutStart_o <= '0';
  58. DoutStop_o <= '0';
  59. DoutValid_o <= '0';
  60. Dout_o <= (others => '0');
  61. s_header <= (others => '0');
  62. s_data <= (others => '0');
  63. s_error <= false;
  64. DinAccept_o <= '1';
  65. s_fsm_state <= GET_HEADER;
  66. when GET_HEADER =>
  67. if (DinValid_i = '1' and DinStart_i = '1') then
  68. s_header <= Din_i;
  69. if (Din_i(3 downto 0) = C_READ and DinStop_i = '1') then
  70. DinAccept_o <= '0';
  71. s_fsm_state <= GET_DATA;
  72. elsif (Din_i(3 downto 0) = C_WRITE and DinStop_i = '0') then
  73. s_fsm_state <= SET_DATA;
  74. else
  75. DinAccept_o <= '0';
  76. s_fsm_state <= IDLE;
  77. end if;
  78. end if;
  79. when GET_DATA =>
  80. if (unsigned(a_addr) <= 7) then
  81. s_data <= s_register(to_integer(unsigned(a_addr)));
  82. else
  83. s_error <= true;
  84. s_data <= (others => '0');
  85. end if;
  86. s_fsm_state <= SEND_HEADER;
  87. when SET_DATA =>
  88. if (DinValid_i = '1') then
  89. DinAccept_o <= '0';
  90. if (DinStop_i = '1') then
  91. if (unsigned(a_addr) <= 7) then
  92. s_register(to_integer(unsigned(a_addr))) <= Din_i;
  93. else
  94. s_error <= true;
  95. end if;
  96. s_fsm_state <= SEND_HEADER;
  97. else
  98. s_fsm_state <= IDLE;
  99. end if;
  100. end if;
  101. when SEND_HEADER =>
  102. DoutValid_o <= '1';
  103. DoutStart_o <= '1';
  104. Dout_o <= s_header;
  105. if (s_dout_accepted) then
  106. DoutValid_o <= '0';
  107. DoutStart_o <= '0';
  108. if (s_header(3 downto 0) = C_WRITE) then
  109. s_fsm_state <= SEND_FOOTER;
  110. else
  111. s_fsm_state <= SEND_DATA;
  112. end if;
  113. end if;
  114. when SEND_DATA =>
  115. DoutValid_o <= '1';
  116. Dout_o <= s_data;
  117. if (s_dout_accepted) then
  118. DoutValid_o <= '0';
  119. s_fsm_state <= SEND_FOOTER;
  120. end if;
  121. when SEND_FOOTER =>
  122. DoutValid_o <= '1';
  123. DoutStop_o <= '1';
  124. Dout_o <= x"01" when s_error else x"00";
  125. if (s_dout_accepted) then
  126. Dout_o <= (others => '0');
  127. DoutValid_o <= '0';
  128. DoutStop_o <= '0';
  129. s_fsm_state <= IDLE;
  130. end if;
  131. when others => null;
  132. end case;
  133. end if;
  134. end process;
  135. FormalG : if Formal generate
  136. signal s_addr : natural range 0 to 15;
  137. type t_cmd is (READ, WRITE, NOP);
  138. signal s_cmd : t_cmd;
  139. type t_vai is record
  140. Start : std_logic;
  141. Stop : std_logic;
  142. Data : std_logic_vector(7 downto 0);
  143. Valid : std_logic;
  144. Accept : std_logic;
  145. end record t_vai;
  146. signal s_job_req : t_vai;
  147. signal s_job_ack : t_vai;
  148. begin
  149. -- VHDL helper logic
  150. process is
  151. begin
  152. wait until rising_edge(Clk_i);
  153. s_job_req <= (DinStart_i, DinStop_i, Din_i, DinValid_i, DinAccept_o);
  154. s_job_ack <= (DoutStart_o, DoutStop_o, Dout_o, DoutValid_o, DoutAccept_i);
  155. if (s_fsm_state = GET_HEADER) then
  156. if (DinValid_i = '1' and DinStart_i = '1') then
  157. s_cmd <= READ when Din_i(3 downto 0) = x"0" else
  158. WRITE when Din_i(3 downto 0) = x"1" else
  159. NOP;
  160. s_addr <= to_integer(unsigned(Din_i(7 downto 4)));
  161. end if;
  162. end if;
  163. end process;
  164. default clock is rising_edge(Clk_i);
  165. -- RESTRICTIONS
  166. -- Initial reset
  167. INITIAL_RESET : restrict {Reset_n_i = '0'[*2]; Reset_n_i = '1'[+]}[*1];
  168. -- CONSTRAINTS
  169. -- Valid stable until accepted
  170. JOB_REQ_VALID_STABLE : assume always
  171. DinValid_i and not DinAccept_o -> next (DinValid_i until_ DinAccept_o);
  172. -- Start stable until accepted
  173. JOB_REQ_START_STABLE : assume always
  174. DinValid_i and not DinAccept_o -> next (DinStart_i = s_job_req.Start until_ DinAccept_o);
  175. -- Stop stable until accepted
  176. JOB_REQ_STOP_STABLE : assume always
  177. DinValid_i and not DinAccept_o -> next (DinStop_i = s_job_req.Stop until_ DinAccept_o);
  178. -- Data stable until accepted
  179. JOB_REQ_DIN_STABLE : assume always
  180. DinValid_i and not DinAccept_o -> next (Din_i = s_job_req.Data until_ DinAccept_o);
  181. -- ASSERTIONS
  182. -- Reset values
  183. AFTER_RESET : assert always
  184. not Reset_n_i
  185. ->
  186. s_fsm_state = IDLE and
  187. not DinAccept_o and
  188. not DoutStart_o and
  189. not DoutStop_o and
  190. not DoutValid_o and
  191. s_register = (0 to 7 => x"00");
  192. -- FSM states in valid range
  193. FSM_STATES_VALID : assert always
  194. s_fsm_state = IDLE or s_fsm_state = GET_HEADER or
  195. s_fsm_state = GET_DATA or s_fsm_state = SET_DATA or
  196. s_fsm_state = SEND_HEADER or s_fsm_state = SEND_DATA or
  197. s_fsm_state = SEND_FOOTER;
  198. -- Discard jobs with invalid command
  199. INV_CMD_DISCARD : assert always
  200. s_fsm_state = GET_HEADER and DinValid_i = '1' and DinStart_i = '1' and
  201. Din_i(3 downto 0) /= x"0" and Din_i(3 downto 0) /= x"1"
  202. ->
  203. next s_fsm_state = IDLE;
  204. -- Discard read job with invalid stop flags
  205. READ_INV_FLAGS_DISCARD : assert always
  206. s_fsm_state = GET_HEADER and DinValid_i = '1' and DinStart_i = '1' and
  207. Din_i(3 downto 0) = x"0" and DinStop_i = '0'
  208. ->
  209. next s_fsm_state = IDLE;
  210. -- Discard write job with invalid stop flags
  211. WRITE_INV_FLAGS_DISCARD : assert always
  212. s_fsm_state = GET_HEADER and DinValid_i = '1' and DinStart_i = '1' and
  213. Din_i(3 downto 0) = x"1" and DinStop_i = '1'
  214. ->
  215. next s_fsm_state = IDLE;
  216. -- After a valid job read request,
  217. -- a job read acknowledge has to follow
  218. READ_VALID_ACK : assert always
  219. {s_fsm_state = GET_HEADER and DinValid_i = '1' and DinStart_i = '1' and
  220. Din_i(3 downto 0) = x"0" and DinStop_i = '1'}
  221. |=>
  222. {-- Job ack header cycle
  223. not DoutValid_o [*];
  224. DoutValid_o and DoutStart_o and not DoutAccept_i [*];
  225. DoutValid_o and DoutStart_o and DoutAccept_i;
  226. -- Job ack data cycle
  227. not DoutValid_o [*];
  228. DoutValid_o and not DoutStart_o and not DoutStop_o and not DoutAccept_i [*];
  229. DoutValid_o and not DoutStart_o and not DoutStop_o and DoutAccept_i;
  230. -- Job ack footer cycle
  231. not DoutValid_o [*];
  232. DoutValid_o and DoutStop_o};
  233. -- After a valid job write request,
  234. -- a job read acknowledge has to follow
  235. WRITE_VALID_ACK : assert always
  236. {s_fsm_state = GET_HEADER and DinValid_i = '1' and DinStart_i = '1' and
  237. Din_i(3 downto 0) = x"1" and DinStop_i = '0';
  238. not DinValid_i [*];
  239. DinValid_i and DinStop_i}
  240. |=>
  241. {-- Job ack header cycle
  242. not DoutValid_o [*];
  243. DoutValid_o and DoutStart_o and not DoutAccept_i [*];
  244. DoutValid_o and DoutStart_o and DoutAccept_i;
  245. -- Job ack footer cycle
  246. not DoutValid_o [*];
  247. DoutValid_o and DoutStop_o};
  248. -- Start & stop flag have to be exclusive
  249. JOB_ACK_NEVER_START_STOP : assert never
  250. DoutStart_o and DoutStop_o;
  251. -- Start & Stop have to be active together with valid
  252. JOB_ACK_START_STOP_VALID : assert always
  253. DoutStart_o or DoutStop_o -> DoutValid_o;
  254. -- Valid has to be stable until accepted
  255. JOB_ACK_VALID_STABLE : assert always
  256. DoutValid_o and not DoutAccept_i -> next (DoutValid_o until_ DoutAccept_i);
  257. -- Start has to be stable until accepted
  258. JOB_ACK_START_STABLE : assert always
  259. DoutValid_o and not DoutAccept_i -> next (DoutStart_o = s_job_ack.Start until_ DoutAccept_i);
  260. -- Stop has to be stable until accepted
  261. JOB_ACK_STOP_STABLE : assert always
  262. DoutValid_o and not DoutAccept_i -> next (DoutStop_o = s_job_ack.Stop until_ DoutAccept_i);
  263. -- Data has to be stable until accepted
  264. JOB_ACK_DOUT_STABLE : assert always
  265. DoutValid_o and not DoutAccept_i -> next (Dout_o = s_job_ack.Data until_ DoutAccept_i);
  266. -- Data from selected address has to be read
  267. READ_DATA : assert always
  268. DoutValid_o and not DoutStart_o and not DoutStop_o and s_addr <= 7
  269. ->
  270. Dout_o = s_register(s_addr);
  271. -- 0 has to be read when invalid address is given
  272. READ_DATA_INV_ADDR : assert always
  273. DoutValid_o and not DoutStart_o and not DoutStop_o and s_addr > 7
  274. ->
  275. Dout_o = x"00";
  276. -- Register has to be written at given address with given data
  277. -- when correct job req write occurs
  278. WRITE_DATA : assert always
  279. -- Job req header cycle
  280. {s_fsm_state = GET_HEADER and DinValid_i = '1' and DinStart_i = '1' and
  281. Din_i(3 downto 0) = x"1" and unsigned(Din_i(7 downto 4)) <= 7 and DinStop_i = '0';
  282. -- Job req data / footer cycle
  283. not DinValid_i [*];
  284. DinValid_i and not DinStart_i and DinStop_i and not DinAccept_o [*];
  285. DinValid_i and not DinStart_i and DinStop_i and DinAccept_o}
  286. |=>
  287. {s_register(s_addr) = s_job_req.Data};
  288. -- FUNCTIONAL COVERAGE
  289. FOOTER_VALID : cover {DoutValid_o = '1' and DoutStop_o = '1' and Dout_o = 8x"0"};
  290. FOOTER_ERR : cover {DoutValid_o = '1' and DoutStop_o = '1' and Dout_o = 8x"1"};
  291. end generate FormalG;
  292. end architecture rtl;