BEGIN { local @INC=('./t', @INC); require TestUtils; import TestUtils qw( create_tidy_test compare_indentation escape ); } use Test::More qw/no_plan/; use File::Temp qw/tempfile/; use strict; use warnings; # Tests that should be added: # all in/out interfaces to tidy_vhdl # tidy_vhdl_file # all indenting structures # tidy_vhdl_file BEGIN { use_ok('Hardware::Vhdl::Tidy'); } for my $desttype (qw(arrayref fileglob stringref subref)) { &test_indent('process lite 1 with destination supplied as '.$desttype, "--process process begin wait on foo; t <= al-foo*5; t <= al-foo; q <= t + bar * x; end process ; -- etc", desttype => $desttype, ); } TODO: { local $TODO = 'Not implemented yet'; $Hardware::Vhdl::Tidy::debug = 0; &test_indent('empty component declaration', "package test_lib is component testsuite end component; component timer port (clk :in std_logic; reset :in std_logic; enable:in std_logic; data :in std_logic_vector (7 downto 0); addr :in std_logic; -- one bit only irq :out std_logic ); end component; end test_lib;", ); &test_indent('process lite 1 with left-aligned multi-line preprocessor commands', "--process process begin wait on foo; #define UARTIO_SPEC \\ signal reset : out std_logic; \\ SIGNAL seluart : out integer range NUARTS-1 DOWNTO 0; \\ SIGNAL host_c : out T_WB_MASTER_CONTROL; \\ SIGNAL host_s : in T_WB_MASTER_STATUS; \\ sourceline : in natural; \\ SIGNAL lineno : out natural q <= t + bar * x; end process ; -- etc", ); for my $ppp ('##', '-- pragma preproc ') { &test_indent("process lite 1 with left-aligned preprocessor prefix='$ppp'", "--process process begin wait on foo; ${ppp}if SIMULATING==1 t <= al-foo*5; ${ppp}else t <= al-foo; ${ppp}endif q <= t + bar * x; end process ; -- etc", preprocessor_prefix => $ppp, ); } } $Hardware::Vhdl::Tidy::debug = 0; $Hardware::Vhdl::Tidy::debug = 1; for my $label ('proclabel', '\\_$! : MY odd procEss label...\\') { for my $type ('', 'postponed ') { &test_indent($type.'process, with all the extras', "--process ${label}: ${type}process ( a, b(1 downto 0), c ) is variable t : integer; begin t <= al-foo; q <= t + bar * x; end ${type}process ${label} ; -- etc"); } } $Hardware::Vhdl::Tidy::debug = 0; &test_indent('process lite 1 with indented preprocessor directives', "--process process begin wait on foo; #if SIMULATING==1 t <= al-foo*5; #else t <= al-foo; #endif q <= t + bar * x; end process ; -- etc", indent_preprocessor => 1, ); &test_indent('record type declaration', "type T_WB_MON_STATUS is record -- controls for putting things in the 'expect' queue - these are for use by helper functions q_ack : bit; -- status reporting retries : natural; nqueued : natural; -- number of transactions that the monitor is expecting end record; -- etc"); &test_indent('physical type declaration', "type T_WB_MON_STATUS is range 0 to integer'high units micron; millimetre = 1000 micron; centimetre = 10000 micron; metre = 100 centimetre; end units; -- etc"); &test_indent('type/access', "type name is access datatype ; -- etc "); &test_indent('architecture, process, loops, generate, min labels', "architecture ArchName of EntName is begin process variable t : integer; begin while t<15 loop -- sequential statements 1 seq1a; seq1b; end loop; for I in A'Range loop -- sequential statements 2 seq2; end loop; loop -- sequential statements 3 seq3; end loop; end process P; G1: for I in A'Range generate -- concurrent statements 1 conc1; end generate; G2: if cond generate -- concurrent statements 2 conc2; end generate; end ArchName; -- etc"); &test_indent('architecture, process, loop, generate, max labels', "architecture ArchName of EntName is begin process variable t : integer; begin L1: for I in A'Range loop -- sequential statements 1 seq1; end loop L1; L2: loop -- sequential statements 2 seq2; end loop L2; end process P; G1: for I in A'Range generate -- concurrent statements 1 conc1; end generate G1; G2: if cond generate -- concurrent statements 2 conc2; end generate G2; end ArchName; -- etc"); &test_indent('architecture, process, if/then/elsif/else/end if', "architecture ArchName of EntName is begin process variable t : integer; begin if a = 1 then b <= 1; elsif a = 2 then b <= 2; else b <= 3; end if; end process; end ArchName; "); for my $type ('', 'postponed ') { &test_indent($type.'process lite 1', "--process ${type}process begin wait on foo; t <= al-foo; q <= t + bar * x; end ${type}process ; -- etc"); } for my $type ('', 'postponed ') { &test_indent($type.'process lite 2', "--process ${type}process variable t : integer; begin wait on foo; t <= al-foo; q <= t + bar * x; end ${type}process ; -- etc"); } for my $type ('', 'pure ', 'impure ') { &test_indent($type.'function definition', "-- definitions ${type}function funcname ( foo : integer; constant bar : integer := 1; signal x:std_logic ) return std_logic_vector( 3 downto 0 ) is alias al is sid; variable t : integer; begin t <= al-foo; return t + bar * x; end function funcname ; -- etc"); } for my $type ('', 'pure ', 'impure ') { &test_indent($type.'function declaration', "-- declaration ${type}function funcname ( foo : integer; constant bar : integer := 1; signal x:std_logic ) return std_logic_vector( 3 downto 0 ) ; -- etc "); } &test_indent('procedure declaration', "-- declaration procedure procname ( foo : integer; constant bar : integer := 1; signal x:inout std_logic ) ; -- etc "); &test_indent('procedure body', "-- declaration procedure procname ( foo : integer; constant bar : integer := 1; signal x:inout std_logic ) is alias al is sid; begin x <= foo + bar; end procedure procname; -- etc"); &test_indent('configuration declaration', "configuration topmixed of top is for structure for b1: blk use entity work.blk(rtl); end for; for b2: blk use entity work.gatelevelblk(synth) port map (ip => ip1, to_int8(x) => y ); end for; for b3: hblkend for b4: subblk use configuration wurble; end for; end for; end for; end topmixed; -- etc"); &test_indent('configuration specifiation', "architecture a of b is begin for instname : compname use entity work.blk(rtl); siggy <= soggy; for i2, i3 : compname2 use entity work.blk(rtl) port map (ip => ip1, to_int8(x) => y ); end archname; "); &test_indent('aggregate', "signal <= ( A => 1, B => 2, ( C or D ) => 3, others => 4 ) ; -- etc "); &test_indent('brackets', "((FOO(( a ) )) b ( c ) )"); &test_indent('misc1', "PACKage bar baz is foo ; foo ; begin foo ( bar baz ) ; bar ; end foo ; "); &test_indent('architecture/component 1', "library ieee; use ieee.std_logic_1164.all; architecture archname of entname is signal siggy, soggy: std_logic_vector(7 downto 0); component mux4 port map ( d : in std_logic; q : out std_logic; ); end component; begin siggy <= soggy; end archname; "); &test_indent('architecture/component 2', "architecture anotherarchname of entname is signal siggy, soggy: std_logic_vector(7 downto 0); component mux4 is generic map ( t : integer ) port map ( d : in std_logic; q : out std_logic; ); end component; begin siggy <= soggy; end architecture anotherarchname; "); &test_indent('syntax summary: entity', "library IEEE; use IEEE.Std_logic_1164.all; entity EntName is port (P1, P2: in Std_logic; P3: out Std_logic_vector(7 downto 0)); end EntName; -- etc"); &test_indent('syntax summary: architecture', "architecture ArchName of EntName is component CompName port (P1: in Std_logic; P2: out Std_logic); end component; signal SignalName, SignalName2: Std_logic := 'U'; begin P: process (P1,P2,P3) -- Either sensitivity list or wait statements! variable VariableName, VarName2: Std_logic := 'U'; begin SignalName <= Expression after Delay; VariableName := Expression; ProcedureCall(Param1, Param2, Param3); wait for Delay; wait until Condition; wait; if Condition then -- sequential statements 1 elsif Condition then -- sequential statements 2 else -- sequential statements 3 end if; case Selection is when Choice1 => -- sequential statements 4 when Choice2 | Choice3 => -- sequential statements 5 when others => -- sequential statements 6 end case; for I in A'Range loop -- sequential statements 7 end loop; end process P; SignalName <= Expr1 when Condition else Expr2; InstanceLabel: CompName port map (S1, S2); L2: CompName port map (P1 => S1, P2 => S2); G1: for I in A'Range generate -- concurrent statements 8 end generate G1; end ArchName; -- etc"); &test_indent('syntax summary: package', "package PackName is type Enum is (E0, E1, E2, E3); subtype Int is Integer range 0 to 15; type Mem is array (Integer range <>) of Std_logic_vector(7 downto 0); subtype Vec is Std_logic_vector(7 downto 0); constant C1: Int := 8; constant C2: Mem(0 to 63) := (others => \"11111111\"); procedure ProcName (ConstParam: Std_logic; VarParam: out Std_logic; signal SigParam: inout Std_logic); function \"+\" (L, R: Std_logic_vector) return Std_logic_vector; end PackName; -- etc"); &test_indent('syntax summary: package body', "package body PackName is procedure ProcName (ConstParam: Std_logic; VarParam: out Std_logic; signal SigParam: inout Std_logic) is -- declarations begin -- sequential statements end ProcName; function \"+\" (L, R: Std_logic_vector) return Std_logic_vector is -- declarations begin -- sequential statements return Expression; end \"+\"; end PackName; -- etc"); &test_indent('syntax summary: configuration', "configuration ConfigName of EntityName is for ArchitectureName for Instances: ComponentName use LibraryName.EntityName(ArchName); end for; end for; end ConfigName; "); &test_indent('architecture, process, case', "architecture ArchName of EntName is begin process variable t : integer; begin case Selection is blah; when Choice1 => t := 1 ; -- sequential statements t:=4; when Choice2 | Choice3 => nested_case: case another_selection is when ab => t:=23; when cd => t := 42; when others => t:=i; t:=sin(t); end case nested_case; when others => t:=5; end case; end process; end ArchName; -- etc"); &test_indent('process lite 1 with left-aligned preprocessor commands', "--process process begin wait on foo; #if SIMULATING==1 t <= al-foo*5; #else t <= al-foo; #endif q <= t + bar * x; end process ; -- etc", ); &test_indent('process lite 1 with initial indent', " --process process begin wait on foo; t <= al-foo*5; q <= t + bar * x; end process ; -- etc", starting_indentation => 1 ); &test_indent('process lite 1 with indentation settings of 3+1', "--process process begin wait on foo; t <= al -foo*5; for x in 1 to 5 loop q <= t + bar * x; end loop; end process ; -- etc", indent_spaces => 3, cont_spaces => 1, ); &test_indent('process lite 1 with indentation settings of 3+0', "--process process begin wait on foo; t <= al -foo*5; q <= t + bar * x; end process ; -- etc", indent_spaces => 3, cont_spaces => 0, ); &test_indent('process lite 1 with indentation settings of 3+1, tab_spaces=4', "--process process begin wait on foo; t <= al \t-foo*5; for x in 1 to 5 loop \t q <= t \t + bar \t * x; end loop; end process ; -- etc", indent_spaces => 3, cont_spaces => 1, tab_spaces => 4, ); &test_indent('process lite 1 with indentation settings of 3+1, tab_spaces=2', "--process process begin \t wait on foo; \t t <= al \t\t-foo*5; \t for x in 1 to 5 loop \t\t\tq <= t \t\t\t + bar \t\t\t * x; \t end loop; end process ; -- etc", indent_spaces => 3, cont_spaces => 1, tab_spaces => 2, ); sub test_indent { my ($testname, $vhdl, %args) = @_; # unpack args my $srctype = 'arrayref'; my $desttype = 'arrayref'; if (exists $args{sourcetype}) { $srctype = $args{sourcetype}; delete $args{sourcetype}; } if (exists $args{desttype}) { $desttype = $args{desttype}; delete $args{desttype}; } # generate the test case (input and desired output) my ($correct_tidy_ref, $untidy_ref) = create_tidy_test($vhdl); # set up the input thing $args{source} = $untidy_ref; # set up the output thing my $tidy_output; if ($desttype eq 'fileglob') { $tidy_output = tempfile; binmode $tidy_output; $args{destination} = $tidy_output; } elsif ($desttype eq 'stringref') { $tidy_output = ''; $args{destination} = \$tidy_output; } elsif ($desttype eq 'arrayref') { $tidy_output = []; $args{destination} = $tidy_output; } elsif ($desttype eq 'subref') { $tidy_output = {}; my $i=0; $args{destination} = sub { $tidy_output->{$i++} = shift; }; } else { die "Unknown dest. type for test_indent: '$desttype'\n"; } # do the thing we want to test! Hardware::Vhdl::Tidy::tidy_vhdl(\%args); # retrieve the results from the output thing # (make $tidy_output an array ref to the output lines) if ($desttype eq 'fileglob') { seek $tidy_output, 0, 0; $tidy_output = [ readline $tidy_output ]; } elsif ($desttype eq 'stringref') { $tidy_output = [ split /(?<=\n)/, $tidy_output ]; } elsif ($desttype eq 'subref') { my @lines; my $i=0; while (exists $tidy_output->{$i}) { push @lines, $tidy_output->{$i++}; } $tidy_output = \@lines; } ok(compare_indentation($correct_tidy_ref, $tidy_output), $testname); }