3

I have a very simple synchronous circuit that is supposed to blink an LED:

module Blinker where

import Clash.Prelude
import Data.Word

{-# NOINLINE topEntity #-}
{-# ANN topEntity
  (Synthesize
    { t_name   = "blinkerTop"
    , t_inputs = [PortName "CLK_32MHZ", PortName "RESET"]
    , t_output = PortName "LED"
    }) #-}
topEntity
  :: Clock System Source
  -> Reset System Asynchronous
  -> Signal System Bit
topEntity = exposeClockReset $ tickTock 32000000

tickTock :: (HiddenClockReset domain gated synchronous) => Word32 -> Signal domain Bit
tickTock n = mealy step (False, 0) (pure ())
  where
    step (s, k) () =
        let k' = k + 1
            finished = k' == n
            s' = if finished then not s else s
            k'' = if finished then 0 else k'
        in ((s', k''), if s' then high else low)

Since it doesn't work when I upload it to a real FPGA board, I thought I'd try it in Xilinx's simulator, with the following testbench:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY testbench IS
END testbench;

ARCHITECTURE behavior OF testbench IS 
    COMPONENT blinkerTop
    PORT(
         CLK_32MHZ : IN  std_logic;
         RESET : IN  std_logic;
         LED : OUT  std_logic
        );
    END COMPONENT;

   signal CLK_32MHZ : std_logic := '0';
   signal RESET : std_logic := '0';
   signal LED : std_logic;
   constant CLK_32MHZ_period : time := 31.2 ns;

BEGIN 
   uut: blinkerTop PORT MAP (
          CLK_32MHZ => CLK_32MHZ,
          RESET => RESET,
          LED => LED
        );

   CLK_32MHZ_process :process
   begin
        CLK_32MHZ <= '0';
        wait for CLK_32MHZ_period/2;
        CLK_32MHZ <= '1';
        wait for CLK_32MHZ_period/2;
   end process;
END;

In the simulator, this matches the real life FPGA board's behaviour: the LED signal stays low.

I looked at the generated VHDL and this is what it looks like:

-- Automatically generated VHDL-93
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
use std.textio.all;
use work.all;
use work.blinkertop_types.all;

entity blinkerTop is
  port(-- clock
       CLK_32MHZ : in std_logic;
       -- asynchronous reset: active high
       RESET     : in std_logic;
       LED       : out std_logic);
end;

architecture structural of blinkerTop is
  signal \#tup_app_arg\       : unsigned(31 downto 0);
  signal \s'\                 : boolean;
  signal \#s'_case_alt\       : boolean;
  signal s                    : boolean;
  signal \#finished_case_alt\ : boolean;
  signal \#k'_case_alt\       : unsigned(31 downto 0);
  signal ds                   : blinkertop_types.tup2;
  signal \#finished_app_arg\  : signed(63 downto 0);
  signal x                    : unsigned(63 downto 0);
  signal x_0                  : blinkertop_types.tup2;
  signal \x#\                 : unsigned(63 downto 0);
  signal k                    : unsigned(31 downto 0);
  signal \#w\                 : unsigned(63 downto 0);
begin
  LED <= '1' when \s'\ else
         '0';

  \#tup_app_arg\ <= resize(to_unsigned(0,64),32) when \#finished_case_alt\ else
                    \#k'_case_alt\;

  \s'\ <= \#s'_case_alt\ when \#finished_case_alt\ else
          s;

  \#s'_case_alt\ <= false when s else
                    true;

  s <= ds.tup2_sel0;

  \#finished_case_alt\ <= tagToEnum(\#finished_app_arg\);

  \#w\ <= (\x#\ + to_unsigned(1,64));

  \#k'_case_alt\ <= resize((resize(\#w\(31 downto 0),64)),32);

  -- register begin 
  blinkertop_register : process(CLK_32MHZ,RESET)
  begin
    if RESET = '1' then
      ds <= ( tup2_sel0 => false, tup2_sel1 => resize(to_unsigned(0,64),32) )
      -- pragma translate_off
      after 1 ps
      -- pragma translate_on
      ;
    elsif rising_edge(CLK_32MHZ) then
      ds <= x_0
      -- pragma translate_off
      after 1 ps
      -- pragma translate_on
      ;
    end if;
  end process;
  -- register end

  \#finished_app_arg\ <= to_signed(1,64) when x = to_unsigned(32000000,64) else to_signed(0,64);

  x <= resize(\#k'_case_alt\,64);

  x_0 <= ( tup2_sel0 => \s'\
         , tup2_sel1 => \#tup_app_arg\ );

  \x#\ <= resize(k,64);

  k <= ds.tup2_sel1;
end;

I noticed that the internal state is not initialized, only assigned on reset. So this gave me an idea to add a reset process to the testbench:

stim_proc: process
begin       
   RESET <= '1';  
   wait for 100 ns; 
   RESET <= '0';
   wait;
end process;

With this change, afterwards I see LED starting to blink in the simulator. [*]

That takes care of the simulation; but how would I ensure a similar reset signal on the real board?

[*] For the simulation, of course, I have increased the frequency from 32,000,000 cycles to just 100 cycles; otherwise I'd have to run the simulator for ages just to see the first transition.

Cactus
  • 27,075
  • 9
  • 69
  • 149
  • Wire your `RESET` input to a slide switch or a press-button of your board? – Renaud Pacalet Aug 01 '18 at 14:48
  • `\s'\ ` wait what? is that a legal VHDL name? The SO parser will not handle it properly – JHBonarius Aug 01 '18 at 14:50
  • 1
    @JHBonarius VHDL extended identifiers (see the LRM, clause 15.4.3). The VHDL parser (if it's a real one) should handle them properly. – Renaud Pacalet Aug 01 '18 at 15:10
  • ***...; but how would I ensure a similar reset signal on the real board?*** This doesn't appear to be a programming question. A Xilinx FPGA would run without a reset unless defaulting to '0''s everywhere locks the design up (It doesn't adding defaults to all your signed/unsigned signal declarations shows). After creating a package blinkertop_types for type tup2, throwing in a function tagToEnum and your testbench simulates. Testing for non-zero in tagToEnum and the led has a period of 20 clocks, testing for zero won't finish in my lifetime. Your board LED is either dim or not toggling. Which? –  Aug 02 '18 at 00:29
  • @user1155120: in my original question, the VHDL was copied from the version I used for simulation, with a transition every 100 cycles instead of every 32,000,000. In the version I run on the hardware, it should be one transition (on -> off or off -> on) per second, so I should be able to see it blinking – Cactus Aug 02 '18 at 01:34
  • @user1155120: I don't have access to the generated code right now, but I'll add the definitions from `blinkertop_types.vhdl` to the question text. – Cactus Aug 02 '18 at 01:39
  • You're asking an XY problem non-programming question. A Xilinx FPGA doesn't need reset (all uninitialized bits are loaded to '0'). For simulation provide initial values to your signed/unsigned values (including record types tup2 - `:= (false,(others => '0'));`and it runs, Boolean defaults to false). You don't provide sufficient information to determine why the board won't run (the cumbersome design could be too slow). Do a simple VHDL implementation directly to board to validate your methodology. What board, what device? Any Xilinx warnings/errors? What's the schematic show? –  Aug 02 '18 at 19:49

1 Answers1

1

One solution is to create a power-on-reset sequence in your FPGA logic. This can be implemented as a counter, and asserting reset as long as the counter value is below some constant. When the counter exceeds the constant value, deassert the reset.

ogre
  • 26
  • 2
  • I ended up doing this in a small VHDL wrapper around my CLaSH code, see e.g. here: https://github.com/gergoerdi/clash-sandbox/blob/c5e5e5362cf4cb0e9f20f7c236e71380fc72717c/projects/brainfuck/src-vhdl/Top.vhdl#L27 – Cactus Sep 07 '18 at 07:00