URL
https://opencores.org/ocsvn/avuc/avuc/trunk
Subversion Repositories avuc
[/] [avuc/] [trunk/] [avuc.pl] - Rev 6
Compare with Previous | Blame | View Log
#!/usr/bin/perl # Create a VHDL entity that implements a program written in a pseudo-assembler language # whose commands are user-defined in VHDL. # # Copyright 2008 by Fernando Blanco <ferblanco@anagramix.com> # # This source file may be used and distributed without # restriction provided that this copyright statement is not # removed from the file and that any derivative work contains # the original copyright notice and the associated disclaimer. # # This source file is free software; you can redistribute it # and/or modify it under the terms of the GNU Lesser General # Public License as published by the Free Software Foundation; # either version 2.1 of the License, or (at your option) any # later version. # # This source is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General # Public License along with this source; if not, download it # from http://www.gnu.org/licenses/lgpl.html $_indent = " "; $_command_key = "tryglspjw2u"; $_line_end = "\n"; @predefined_ucode = ( "nop", "jump" ); %predefined_label = ( "begin" => 0, "end" => 1); use Getopt::Std; use File::Basename; $prog_name='avuc.pl'; $ver='1.0'; getopts( 'o:dvh', \%opt ) or usage(); usage() if $opt{h}; sub usage() { print "$prog_name version $ver\n"; print "Creates a VHDL file that runs a program based on assembler with VHDL user-defined commands\n"; print "Usage: $prog_name [flags] infile\n"; print " -o output filename\n"; print " -h show this help\n"; print " -v verbose\n"; print " -d debugging information\n"; exit; } $debug = 1 if $opt{d}; $verbose = 1 if ( $opt{v} || $opt{d} ); print "=====================================\n$prog_name version $ver\n" if ($verbose); # Opening input file: $ifile_name = $ARGV[0]; if ( !$ifile_name ) { usage() } print "Input file: $ifile_name\n" if $verbose; open IFILE, "< $ifile_name" or die "\'$ifile_name\' cannot be opened\n$!"; # fileparse_set_fstype(MSWin32); fileparse_set_fstype(Linux); ($base_ifile, $path_ifile, $type) = fileparse($ifile_name, '\.usm'); # Opening output file: $ofile_name = $path_ifile . $base_ifile . '.vhd'; if ( $opt{o} ) { $ofile_name = $opt{o}; } print "Output file: $ofile_name\n" if $verbose; open OFILE, "> $ofile_name" or die "\'$ofile_name\' cannot be opened\n$!"; ################## usm definitions file reading ###################### @usm_ucode = @predefined_ucode; $usm_cycle_bus_width = 1; $usmc_error_no = 0; $usmc_line_no = 0; $read_next_line = "yes"; while (1) { if ( $read_next_line =~ /yes/ ) { $read_line = <IFILE>; if (eof) { &print_message_end_usm; } $usmc_line_no++; } $read_next_line = "yes"; $_ = $read_line; split; $_ = $_[0]; if (/^&\$(.*)/) { print "Line $usmc_line_no: Command '$1' found\n" if ($verbose); if ($1 =~ /^end_usm$/) {last;} $_ = '&rd_'.$1.'(@_);'; @_ = eval $_; # print "$@" if ($@ ); print "Line $usmc_line_no: Error: &\$"."$1 function not implemented\n" if ($@ ); if ($_[0] =~ /^$_command_key$/) { $read_line = $_[1]; $read_next_line = "no"; } } }; print "File read finished. $usmc_error_no errors found\n************************\n"; if ( $usmc_error_no ) { exit; } ######################### VHDL file writing ########################## #Header, include & entity: @time = localtime(time); $time[4] += 1; $time[5] += 1900; print OFILE "-- File generated by $prog_name ($time[3]/$time[4]/$time[5])$_line_end--$_line_end"; print OFILE @usm_header; print OFILE @usm_include; &wr_entity; # Architecture: print OFILE "$_line_end$_line_end"."architecture program of $usm_entity is$_line_end$_line_end"; print OFILE @usm_sig_declaration, $_line_end; $usm_opcode_bus_width = &bus_width( $#usm_ucode + keys %usm_jump_code ); # print "$usm_opcode_bus_width, $#usm_ucode"; exit; $usm_pc_bus_width = &bus_width( $usmc_prog_line_no ); if ($usm_pc_bus_width > $usm_data_bus_width) { $usm_data_bus_width = $usm_pc_bus_width; } $usm_opcode_format = "%0".$usm_opcode_bus_width."b"; $usm_pc_format = "%0".$usm_pc_bus_width."b"; $usm_data_format = "%0".$usm_data_bus_width."b"; &wr_sig_decl_breg; &wr_sig_decl_clist; &wr_sig_decl_llist; &wr_sig_decl_ulist; # Processes: print OFILE "$_line_end"."begin$_line_end$_line_end"; print OFILE "--***************************** Program processes *****************************--$_line_end"; &wr_proc_init; &wr_program; print OFILE "--************************** Jump & cycle processes ***************************--$_line_end"; &wr_jump; print OFILE "--**************************** Drivers processes ******************************--$_line_end"; &wr_drivers; print OFILE "--******************************** Extra code *********************************--$_line_end"; print OFILE @usm_extra_code; print OFILE "$_line_end"."end program;$_line_end"; exit; ########################################################################## ########################### Defined arrays ############################### ########################################################################## # # %usm_opcode = (drivers_name_1, $uref_1, drivers_name_2, $uref_2, ... ); # $uref_1 = {ucode_name_1 => $cref_1, ucode_name_2 => $cref_2, ...}; # $cref_1 = {cycle_1 => $lref_1, cycle_2 => $lref_2, ...}; # $lref_1 = [line_1, line_2 ...]; # # @usm_ucode = (@predefined_ucode, ucode_name_1, ucode_name_2, ...); # # %usm_jump_code = (jump_code_name_1 => condition_1, jump_code_name_2 => condition_2, ...); # # @usm_comment = (prog_line_0_comments, prog_line_1_comments, ...); # # @usm_command = (prog_line_0_command, prog_line_1_command, ...); # # @usm_data = (prog_line_0_data, prog_line_1_data, ...); # # %usm_label = (label_name_0 => prog_line_label_0, label_name_1 => prog_line_label_1, ...}; # ################################################################################## ################################# Subroutines #################################### ################################################################################## # Calculates the necessary bus width to hold a vector with maximum value $_[0]: sub bus_width { use integer; my($i, $aux) = (0, $_[0]); while ($aux != 1) { $aux /= 2; ++$i; } return ++$i; } ############################### Read subroutines ################################# # Reads the name of the main clock: sub print_message_end_usm { print "Error: Ending command 'end_usm' not found\n"; $usmc_error_no++; print "$usmc_error_no errors found\n************************\n"; exit; } # Reads a line, returns 1 if the first word is a command, 0 if not: sub line_first_word { my $remove_trail_blanks = $_[0]; $read_line = <IFILE>; if (eof) { &print_message_end_usm; } $usmc_line_no++; $read_line =~ s/[$_line_end]+//; # remove end of line (Linux/DOS) if ( $remove_trail_blanks ) { $read_line =~ s/\s*(.*)/\1/; } # print "$read_line#$1\n"; # if ( $usmc_line_no > 24 ) { exit; } # if ( $usmc_line_no > 90 && $usmc_line_no < 110 ) { $read_line = $read_line . $_line_end; @split_line = split (/\s+/, $read_line); $_ = $split_line[0]; if (/^&\$(.*)/) { $read_command = $1; return 1; } return 0; } # Reads the name of the main clock: sub rd_clock { $usm_main_clk = $_[1]; } # Reads the data bus minimum length: sub rd_data_bus_min_width { $usm_data_bus_width = $_[1]; } # Reads the name of the entity to create: sub rd_entity { $usm_entity = $_[1]; } # Reads the output file header: sub rd_header { while (1) { if ( &line_first_word(1) ) { return $_command_key, $read_line; } push(@usm_header, $read_line); } } # Reads the VHDL include text: sub rd_include { while (1) { if ( &line_first_word(1) ) { return $_command_key, $read_line; } push(@usm_include, $read_line); } } # Reads the VHDL generic parameters: sub rd_generic { while (1) { if ( &line_first_word(1) ) { return $_command_key, $read_line; } if ( $read_line !~ /^$_line_end+/ ) { push(@usm_generic, $read_line); } } } # Reads the VHDL port signals: sub rd_port { while (1) { if ( &line_first_word(1) ) { return $_command_key, $read_line; } if ( $read_line !~ /^$_line_end+/ ) { push(@usm_port, $read_line); } } } # Reads the VHDL internal signals declarations: sub rd_sig_declaration { while (1) { if ( &line_first_word(1) ) { return $_command_key, $read_line; } push(@usm_sig_declaration, $read_line); } } # Reads opcodes: sub rd_opcode_def { my $opcode, $ucode, %cycles = (), %ucodes = (); $opcode = $_[1]; while ( !&line_first_word(1) ) {} do { $ucode = $read_command; print "Line $usmc_line_no: Action '$ucode' found\n" if ($verbose); if ( $ucode !~ /^default$/ ) { while ( !&line_first_word(1) ) {} if ( $read_command !~ /^cycle_def$/ ) { print "Line $usmc_line_no: Error: 'cycle_def' expected instead of '$read_command'\n"; $usmc_error_no++; } } do { $cycle_def_no = $split_line[1]; # print "$opcode-$ucode-$cycle_def_no\n"; if ($cycle_def_no > $usm_cycle_bus_width) { $usm_cycle_bus_width = $cycle_def_no; } --$cycle_def_no; # Lines capture for this ucode: my @cycle_lines = (); while ( !&line_first_word(1) ) { push(@cycle_lines, $read_line); } # print "WW @cycle_lines"; if ( $ucode =~ /^default$/ ) { # default - VHDL lines: $ucodes{$ucode} = [ @cycle_lines ]; } else { # Hash cycle number - VHDL lines: $cycles{$cycle_def_no} = [ @cycle_lines ]; # ucode name - cycles hash: $ucodes{$ucode} = { %cycles }; } # opcode name - ucodes hash: $usm_opcode{$opcode} = { %ucodes }; # print "^^ $usm_opcode{$opcode}{$ucode}{$cycle_def_no}[0]"; } while ( $read_command =~ /^cycle_def$/ ); # opcode list: push (@usm_ucode, $ucode); } while ( $read_command !~ /^end_opcode_def$/ ); } # Reads jumps: sub rd_jump_opcode_def { my $jump_type, $jump_type; while ( !&line_first_word(1) ) {} if ( $read_command !~ /^condition$/ ) { print "Line $usmc_line_no: Error: 'condition' expected instead of '$read_command'\n"; $usmc_error_no++; } do { $jump_type = $split_line[1]; print "Line $usmc_line_no: Jump '$jump_type' found\n" if ($verbose); # Condition capture: $condition = ""; while ( !&line_first_word(1) ) { $read_line =~ s/[$_line_end]+//; $condition = $condition . $read_line . " "; } $usm_jump_code{$jump_type} = $condition; } while ( $read_command =~ /^condition$/ ); return $_command_key, $read_line; } # Reads the program: sub rd_prog_code { my $command, $label, $prog_line_no = 0; @usm_comment = (); %usm_label = %predefined_label; while (1) { if ( &line_first_word(1) ) { last; } # print "--$prog_line_no: $read_line--"; if ($read_line =~ /^$_line_end/) { next; } #Comments capture: if ($read_line =~ /^--.*/) { $usm_comment[$prog_line_no] .= $read_line; next; } #Label capture: if ($read_line =~ s/^(.*):\s*//) { $label = $1; if ( exists $usm_label{$label} ) { print "Line $usmc_line_no: Error: Label '$label' has already been defined\n"; $usmc_error_no++; } $usm_label{$label} = $prog_line_no; print "LL $prog_line_no, $label\n" if ($debug); } split( /\s+/, $read_line ); $usm_command[$prog_line_no] = shift @_; $usm_data[$prog_line_no] = "@_"; print "CM $usm_command[$prog_line_no]\n" if ($debug); print "DT $usm_data[$prog_line_no]\n" if ($debug); $command = $usm_command[$prog_line_no]; { if ( grep(/^$command$/, @usm_ucode) ) { next; } if ( exists $usm_jump_code{$command} ) { next; } print "Line $usmc_line_no: Error: '$command' is not a valid opcode\n"; $usmc_error_no++; } $prog_line_no++; } $usmc_prog_line_no = $prog_line_no; $usm_label{"end"} = $usmc_prog_line_no; $usm_command[$usmc_prog_line_no] = "jump"; $usm_data[$usmc_prog_line_no] = "end"; &s_label_err; return $_command_key, $read_line; } # Search for label errors: sub s_label_err { foreach $index (0 .. $#usm_command ) { $command = $usm_command[$index]; if ( $command =~ /^jump$/ || exists $usm_jump_code{$command} ) { $label = $usm_data[$index]; if ( !exists $usm_label{$label} ) { print "Error: '$label' is not a valid label in\n '$command $label' (prog_code: $index)\n"; $usmc_error_no++; } } } } # Reads the extra VHDL code: sub rd_extra_code { while (1) { if ( &line_first_word(0) ) { return $_command_key, $read_line; } push(@usm_extra_code, $read_line); } } ############################### Write subroutines ################################# # Writes a number of indentation segments: sub indent { my($i); for ($i = 0; $i < $_[0]; ++$i) { print OFILE "$_indent"; } } # Writes entity header: sub wr_entity { print OFILE "$_line_end"."entity $usm_entity is$_line_end"; if ( @usm_generic ) { &indent(1); print OFILE "generic ($_line_end"; foreach $line ( @usm_generic ) { &indent(2); print OFILE $line; } &indent(1); print OFILE ");$_line_end"; } &indent(1); print OFILE "port ($_line_end"; &indent(2); print OFILE "-- To start the program:$_line_end"; &indent(2); print OFILE "avuc_start: in std_logic;$_line_end"; &indent(2); print OFILE "-- To stop the program:$_line_end"; &indent(2); print OFILE "avuc_rst: in std_logic;$_line_end"; foreach $line ( @usm_port ) { &indent(2); print OFILE $line; } &indent(2); print OFILE "-- State of the program (running/stopped):$_line_end"; &indent(2); print OFILE "avuc_state: out std_logic$_line_end"; &indent(1); print OFILE ");$_line_end"."end $usm_entity;$_line_end"; } # Writes signal declaration of usm basic registers: sub wr_sig_decl_breg { print OFILE "-- Basic registers of usm:$_line_end"; printf OFILE "signal usm_opcode: std_logic_vector(%u downto 0);$_line_end", $usm_opcode_bus_width-1; printf OFILE "signal usm_pc: std_logic_vector(%u downto 0) := (others => '1');$_line_end", $usm_pc_bus_width-1; printf OFILE "signal usm_data: std_logic_vector(%u downto 0);$_line_end", $usm_data_bus_width-1; printf OFILE "signal usm_cyclesno: std_logic_vector(%u downto 0);$_line_end", $usm_cycle_bus_width-1; print OFILE "-- Cycles counter:$_line_end"; printf OFILE "signal usm_cy: std_logic_vector(%u downto 0);$_line_end", $usm_cycle_bus_width; print OFILE "-- usm_cy(0) delayed 1 clock:$_line_end"; print OFILE "signal usm_cy_0_d1: std_logic;$_line_end"; print OFILE "-- To avoid usm_cy deadlock:$_line_end"; print OFILE "signal usm_cy_rst: std_logic;$_line_end$_line_end"; } # Writes signal declaration of usm commands: sub wr_sig_decl_clist { my $ucode; print OFILE "-- Commands list:$_line_end"; foreach $index ( 0 .. $#usm_ucode ) { $ucode = $usm_ucode[$index]; print OFILE "constant USMO_" . uc($ucode) . ":$_line_end"; &indent(3); printf OFILE "std_logic_vector(usm_opcode'range) := \"$usm_opcode_format\";$_line_end", $index; } $index = 1; foreach $jump ( keys %usm_jump_code ) { # $ucode = $usm_jump_code{$jump}; print OFILE "constant USMO_" . uc($jump) . ":$_line_end"; &indent(3); printf OFILE "std_logic_vector(usm_opcode'range) := \"$usm_opcode_format\";$_line_end", $#usm_ucode + $index; ++$index; } print OFILE $_line_end; } # Writes signal declaration of usm labels: sub wr_sig_decl_llist { my $label; print OFILE "-- Labels list:$_line_end"; foreach $index ( keys %usm_label ) { $label = $index; printf OFILE "constant USML_%s:$_line_end", uc($label); &indent(3); printf OFILE "std_logic_vector(usm_pc'range) := \"$usm_pc_format\";$_line_end", $usm_label{$index}; } print OFILE $_line_end; } # Writes signal declaration of usm ucodes: sub wr_sig_decl_ulist { my $ucode; print OFILE "-- usm_pc reset:$_line_end"; print OFILE "signal avuc_start_d: std_logic_vector(2 downto 0);$_line_end"; print OFILE "signal avuc_rst_d: std_logic_vector(2 downto 0);$_line_end"; print OFILE "signal stup_rst, stup_rst_d1: std_logic;$_line_end"; print OFILE "signal stup_rst_cnt: std_logic_vector(5 downto 0) := (others => '0');$_line_end"; print OFILE "signal usm_pc_gt_end: std_logic;$_line_end"; print OFILE "signal usm_pc_ldini_init_d1: std_logic;$_line_end"; print OFILE "signal usm_pc_ldend_init_d1: std_logic;$_line_end"; print OFILE "-- usm_pc microcodes:$_line_end"; print OFILE "signal usm_pc_inc: std_logic;$_line_end"; print OFILE "signal usm_pc_ldjmp: std_logic;$_line_end"; print OFILE "signal usm_pc_ldini: std_logic;$_line_end"; print OFILE "signal usm_pc_ldend: std_logic;$_line_end"; print OFILE "-- Remaining microcodes:$_line_end"; # foreach $index ( 0 .. $#usm_ucode ) { # $ucode = $usm_ucode[$index]; # if ( grep(/^$ucode$/, @predefined_ucode) ) { next; } # printf OFILE "signal usm_%s: std_logic;$_line_end", $ucode; # } foreach $driver ( keys %usm_opcode ) { foreach $ucode ( keys %{ $usm_opcode{$driver} } ) { if ( $ucode !~ /^default$/ ) { foreach $cycle_no ( keys % { $usm_opcode{$driver}->{$ucode} } ) { print OFILE "signal usm_$ucode"."_$cycle_no".": std_logic;$_line_end"; } } } } print OFILE $_line_end; } # Writes initial process: sub wr_proc_init { print OFILE "-- Program start/stop/state:$_line_end"; print OFILE "p_prog_init: process($usm_main_clk)$_line_end"; print OFILE "variable usm_pc_ld_init_var: std_logic;$_line_end"; print OFILE "begin$_line_end"; &indent(1); print OFILE "if rising_edge($usm_main_clk) then$_line_end"; &indent(2); print OFILE "-- Program start:$_line_end"; &indent(2); print OFILE "avuc_start_d(0) <= avuc_start;$_line_end"; &indent(2); print OFILE "avuc_start_d(1) <= avuc_start_d(0);$_line_end"; &indent(2); print OFILE "avuc_start_d(2) <= avuc_start_d(1);$_line_end"; &indent(2); print OFILE "usm_pc_ld_init_var := avuc_start_d(1) and not avuc_start_d(2);$_line_end"; &indent(2); print OFILE "usm_pc_ldini_init_d1 <= usm_pc_ld_init_var;$_line_end"; &indent(2); print OFILE "usm_pc_ldini <= usm_pc_ld_init_var or usm_pc_ldini_init_d1; -- 2 clocks long$_line_end"; &indent(2); print OFILE "-- Program stop:$_line_end"; &indent(2); print OFILE "if stup_rst = '1' then$_line_end"; &indent(3); print OFILE "stup_rst_cnt <= stup_rst_cnt + 1;$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(2); print OFILE "stup_rst <= '0';$_line_end"; &indent(2); print OFILE "if stup_rst_cnt(5 downto 4) /= 2 then$_line_end"; &indent(3); print OFILE "stup_rst <= '1';$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(2); print OFILE "stup_rst_d1 <= stup_rst;$_line_end"; &indent(2); print OFILE "usm_pc_gt_end <= '0';$_line_end"; &indent(2); print OFILE "if usm_pc > USML_END and usm_pc_gt_end = '0' then$_line_end"; &indent(3); print OFILE "usm_pc_gt_end <= '1';$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(2); print OFILE "avuc_rst_d(0) <= avuc_rst;$_line_end"; &indent(2); print OFILE "avuc_rst_d(1) <= avuc_rst_d(0);$_line_end"; &indent(2); print OFILE "avuc_rst_d(2) <= avuc_rst_d(1);$_line_end"; &indent(2); print OFILE "usm_pc_ld_init_var := usm_pc_gt_end or (not stup_rst and stup_rst_d1) or$_line_end"; &indent(15); print OFILE "( avuc_rst_d(1) and not avuc_rst_d(2) );$_line_end"; &indent(2); print OFILE "usm_pc_ldend_init_d1 <= usm_pc_ld_init_var;$_line_end"; &indent(2); print OFILE "usm_pc_ldend <= usm_pc_ld_init_var or usm_pc_ldend_init_d1; -- 2 clocks long$_line_end"; &indent(2); print OFILE "-- Program state:$_line_end"; &indent(2); print OFILE "avuc_state <= AVUC_STATE_RUNNING;$_line_end"; &indent(2); print OFILE "if usm_pc = USML_END then$_line_end"; &indent(3); print OFILE "avuc_state <= AVUC_STATE_STOPPED;$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(1); print OFILE "end if;$_line_end"; print OFILE "end process p_prog_init;$_line_end$_line_end"; } # Writes program: sub wr_program { my $comment, $ucode_prog, $cycle_no_max, $data; print OFILE "p_usm_prog_code: process(usm_pc)$_line_end"; print OFILE "begin$_line_end"; &indent(1); print OFILE "usm_data <= (others => '-');$_line_end"; &indent(1); print OFILE "case usm_pc is$_line_end"; foreach $prog_line ( 0 .. $usmc_prog_line_no ) { &indent(1); printf OFILE "when \"$usm_pc_format\" =>$_line_end", $prog_line; # Comments: $comment = $usm_comment[$prog_line]; if ( $comment ) { &indent(2); print OFILE "$comment"; } # usm_opcode: $ucode_prog = $usm_command[$prog_line]; &indent(2); print OFILE "usm_opcode <= USMO_".uc($ucode_prog).";$_line_end"; # usm_cyclesno: $cycle_no_max = 0; if ( !grep(/^$ucode_prog/, @predefined_ucode) && !exists $usm_jump_code{$ucode_prog} ) { outer_loop: foreach $driver (keys %usm_opcode) { foreach $ucode ( keys %{ $usm_opcode{$driver} } ) { if ( $ucode =~ /^$ucode_prog$/ ) { foreach $cycle_no ( keys %{$usm_opcode{$driver}->{$ucode} } ) { if ( $cycle_no > cycle_no_max ) { $cycle_no_max = $cycle_no; } } last outer_loop; } } } } &indent(2); printf OFILE "usm_cyclesno <= (%u => '1', others => '0');$_line_end", $cycle_no_max; # usm_data: $data = $usm_data[$prog_line]; if ( !$data =~ /\D/ ) { &indent(2); printf OFILE "usm_data <= \"$usm_data_format\";$_line_end", $data; } elsif ( exists $usm_label{$data} ) { &indent(2); printf OFILE "usm_data <= \"$usm_data_format\";$_line_end", $usm_label{$data}; } elsif ( $data ) { &indent(2); printf OFILE "usm_data(%u downto 0) <= %s;$_line_end", $usm_data_bus_width-1, $data; } } &indent(1); print OFILE "when others =>$_line_end"; &indent(2); print OFILE "usm_opcode <= (others => '-');$_line_end"; &indent(2); print OFILE "usm_cyclesno <= (others => '-');$_line_end"; &indent(1); print OFILE "end case;$_line_end"; print OFILE "end process p_usm_prog_code;$_line_end$_line_end"; } # Writes jump processes: sub wr_jump { # pc counter process: print OFILE "p_usm_pc_drv: process($usm_main_clk)$_line_end"; print OFILE "variable var_aux: std_logic_vector(3 downto 0);$_line_end"; print OFILE "begin$_line_end"; &indent(1); print OFILE "if rising_edge($usm_main_clk) then$_line_end"; &indent(2); print OFILE "-- usm_pc_inc (increment usm_pc):$_line_end"; &indent(2); print OFILE "usm_pc_inc <= '0';$_line_end"; &indent(2); print OFILE "if usm_cy = usm_cyclesno and usm_pc_ldini_init_d1 = '0' then$_line_end"; &indent(3); print OFILE "usm_pc_inc <= '1';$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(2); print OFILE "-- usm_pc_ldjmp (load usm_pc with usm_data):$_line_end"; &indent(2); print OFILE "usm_pc_ldjmp <= '0';$_line_end"; &indent(2); print OFILE "case usm_opcode is$_line_end"; &indent(2); print OFILE "when USMO_JUMP =>$_line_end"; &indent(3); print OFILE "usm_pc_ldjmp <= '1';$_line_end"; foreach $jump ( keys %usm_jump_code ) { &indent(2); print OFILE "when USMO_".uc($jump)." =>$_line_end"; &indent(3); print OFILE "if $usm_jump_code{$jump}then$_line_end", ; &indent(4); print OFILE "usm_pc_ldjmp <= '1';$_line_end"; &indent(3); print OFILE "end if;$_line_end"; } &indent(2); print OFILE "when others =>$_line_end"; &indent(3); print OFILE "usm_pc_ldjmp <= '0';$_line_end"; &indent(2); print OFILE "end case;$_line_end"; &indent(2); print OFILE "-- usm_pc:$_line_end"; &indent(2); print OFILE "usm_cy_0_d1 <= usm_cy(0) and not usm_pc_ldini_init_d1;$_line_end"; &indent(2); print OFILE "var_aux := usm_pc_ldini & usm_pc_ldend & (usm_pc_ldjmp and usm_cy_0_d1) & usm_pc_inc;$_line_end"; &indent(2); print OFILE "case var_aux is$_line_end"; &indent(2); print OFILE "when \"0000\" =>$_line_end"; &indent(3); print OFILE "null;$_line_end"; &indent(2); print OFILE "when \"0001\" =>$_line_end"; &indent(3); print OFILE "usm_pc <= usm_pc + 1;$_line_end"; &indent(2); print OFILE "when \"0010\" | \"0011\" =>$_line_end"; &indent(3); print OFILE "usm_pc <= usm_data(usm_pc'range);$_line_end"; &indent(2); print OFILE "when \"0100\" | \"0101\" | \"0110\" | \"0111\" =>$_line_end"; &indent(3); print OFILE "usm_pc <= USML_END;$_line_end"; &indent(2); print OFILE "when \"1000\" | \"1001\" | \"1010\" | \"1011\" | \"1100\" | \"1101\" | \"1110\" | \"1111\" => -- 1XXX$_line_end"; &indent(3); print OFILE "usm_pc <= USML_BEGIN;$_line_end"; &indent(2); print OFILE "when others =>$_line_end"; &indent(4); print OFILE "null;$_line_end"; print OFILE "-- usm_pc <= USML_BEGIN;$_line_end"; &indent(2); print OFILE "end case;$_line_end"; &indent(1); print OFILE "end if;$_line_end"; print OFILE "end process p_usm_pc_drv;$_line_end$_line_end"; # Cycle process: printf OFILE "p_usm_cy_drv: process(%s)$_line_end", $usm_main_clk; print OFILE "begin$_line_end"; &indent(1); printf OFILE "if rising_edge(%s) then$_line_end", $usm_main_clk; &indent(2); print OFILE "usm_cy_rst <= '0';$_line_end"; &indent(2); print OFILE "if usm_cy = 0 then$_line_end"; &indent(3); print OFILE "usm_cy_rst <= '1';$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(2); print OFILE "-- usm_cy:$_line_end"; &indent(2); print OFILE "if usm_pc_inc = '1' or (usm_pc_ldjmp = '1' and usm_cy_0_d1 = '1') or$_line_end"; &indent(12); print OFILE "usm_pc_ldini_init_d1 = '1' or usm_cy_rst = '1' then$_line_end"; &indent(3); print OFILE "usm_cy <= (0 => '1', others => '0');$_line_end"; &indent(2); print OFILE "else$_line_end"; &indent(3); print OFILE "usm_cy(0) <= '0';$_line_end"; &indent(3); print OFILE "for i in usm_cy'range loop$_line_end"; &indent(4); print OFILE "if i /= 0 then$_line_end"; &indent(5); print OFILE "usm_cy(i) <= usm_cy(i-1);$_line_end"; &indent(4); print OFILE "end if;$_line_end"; &indent(3); print OFILE "end loop;$_line_end"; &indent(2); print OFILE "end if;$_line_end"; &indent(1); print OFILE "end if;$_line_end"; print OFILE "end process p_usm_cy_drv;$_line_end$_line_end"; } # Writes drivers: sub wr_drivers { my %ucode_hash_uc, %ucode_hash_act, %ucode_one_hot, $index_ucode; foreach $driver ( keys %usm_opcode ) { # Auxiliary hashes: %ucode_hash_uc = %{ $usm_opcode{$driver} }; %ucode_hash_act = (); foreach $ucode ( keys %{ $usm_opcode{$driver} } ) { if ( $ucode !~ /^default$/ ) { foreach $cycle_no ( keys %{ $usm_opcode{$driver}->{$ucode} } ) { $ucode_hash_act{"$ucode"."_"."$cycle_no"} = $usm_opcode{$driver}->{$ucode}->{$cycle_no} ; } } } # Process beginning: print OFILE "$_line_end"; print OFILE "p_usm_$driver"."_drv: process($usm_main_clk)$_line_end"; $var_data_bus_width = scalar(keys %ucode_hash_act); $var_data_format = "%0".$var_data_bus_width."b"; printf OFILE "variable %s_var: std_logic_vector(%u downto 0);$_line_end", $driver, $var_data_bus_width-1; print OFILE "begin$_line_end"; &indent(1); print OFILE "if rising_edge($usm_main_clk) then$_line_end"; # Microcodes: foreach $ucode ( keys %ucode_hash_uc ) { if ( $ucode !~ /^default$/ ) { &indent(2); print OFILE "-- $ucode:$_line_end"; foreach $cycle_no ( keys %{ $ucode_hash_uc{$ucode} } ) { &indent(2); printf OFILE "usm_$ucode"."_$cycle_no <= '0';$_line_end"; } &indent(2); print OFILE "if usm_opcode = USMO_".uc($ucode)." then$_line_end"; foreach $cycle_no ( keys %{ $ucode_hash_uc{$ucode} } ) { &indent(3); printf OFILE "if usm_cy(%u) = '1' then$_line_end", $cycle_no; &indent(4); print OFILE "usm_$ucode"."_$cycle_no <= '1';$_line_end"; &indent(3); print OFILE "end if;$_line_end"; } &indent(2); print OFILE "end if;$_line_end"; } } # Actions: &indent(2); print OFILE "-- Actions:$_line_end"; &indent(2); print OFILE "$driver"."_var := "; $index_ucode = 0; foreach $ucode ( keys %ucode_hash_act ) { if ( $index_ucode ) { print OFILE " & "; } $ucode_one_hot{$ucode} = ""; foreach $index_one_hot ( 0 .. $var_data_bus_width-1) { $bit = 0; if ( $index_ucode == $index_one_hot ) { $bit = 1; } $ucode_one_hot{$ucode} .= $bit; } print OFILE "usm_$ucode"; ++$index_ucode; } print OFILE ";$_line_end"; &indent(2); print OFILE "case $driver"."_var is$_line_end"; &indent(2); printf OFILE "when \"$var_data_format\" =>", 0; if ( defined($usm_opcode{$driver}->{default}) ) { print OFILE $_line_end; foreach $line ( @{ $usm_opcode{$driver}->{default} } ) { &indent(3); print OFILE $line; } } else { print OFILE " null;$_line_end"; } foreach $ucode ( keys %ucode_hash_act ) { &indent(2); print OFILE "when \"$ucode_one_hot{$ucode}\" =>$_line_end"; foreach $line ( @{ $ucode_hash_act{$ucode} } ) { &indent(3); print OFILE $line; } } &indent(2); print OFILE "when others => null;$_line_end"; &indent(2); print OFILE "end case;$_line_end"; # End process: &indent(1); print OFILE "end if;$_line_end"; print OFILE "end process p_usm_"."$driver"."_drv;$_line_end$_line_end"; } }