#!/usr/bin/perl #****************************************************************** # # mbctrl module # #****************************************************************** # # VCL Confidential Copyright © 2009 UC Davis ECE Department # #****************************************************************** # # created on: 3/23/2009 # created by: jwwebb # last edit on: $DateTime: $ # last edit by: $Author: $ # revision: $Revision: $ # comments: Generated # #****************************************************************** # Revision List: # # 1.0 3/23/2009 Initial release # 1.1 5/07/2009 Added Block RAM Pattern Upload, # Data Path FPGA Configuration, # ILB Read/Write Register(s). # #****************************************************************** # Measurement Board Control # # This utility is intended to control the Measurement Board through # the RS-232 interface connected to the Control FPGA. # # # Usage Information: # # Usage: ./ctrl.pl [-h] [-v] [-s] [-a] [-d] [-g] [-l ] [-f ] # [-b ] [-r | -w] [-i ] [-j ] # # # -h Print Help. # -v Verbose: Print Debug Information. # -c COM Port Settings: [PORT]. # -l Set LEDs On or Off (00 to FF, hexadecimal). # -a Configure AD9516. # -d Configure DAC5682Z. # -s Reset Peripherals. # -f Configure Data Path FPGA. # -b Block RAM User Pattern for Data Path FPGA. # -i ILB Address for Data Path FPGA. # -j ILB Data for Data Path FPGA. # -r ILB Read Command for Data Path FPGA. # -w ILB Write Command for Data Path FPGA. # -g Enable Block RAM Patterns in Data Path FPGA. # # Example: # ./ctrl.pl -c 4 -v -l 0 # ./ctrl.pl -c 4 -v -a # ./ctrl.pl -c 4 -v -d # ./ctrl.pl -c 4 -v -f sig_dp_cfg.hex # #****************************************************************** #****************************************************************** # CPAN Modules #****************************************************************** use strict; use FileHandle; use POSIX; use Getopt::Std; use Time::HiRes qw( usleep ); #****************************************************************** # Constants and Variables: #****************************************************************** my (%opts)=(); my ($led); my ($ad9516); my ($dac5682); my ($cfg_dp); my ($reset); my ($bram); my ($read); my ($write); my ($addr); my ($data); my ($bram_nsram); my ($debug); my ($port); my ($speed) = "115200"; my ($bits) = "8"; my ($parity) = "N"; my ($stop) = "1"; our $comfh; my (%ctrlH, $ctrl_rH); #****************************************************************** # Retrieve command line argument #****************************************************************** getopts('hvc:adl:f:s:b:i:j:rwg',\%opts); my $optslen = scalar( keys %opts ); print("Number of Options on Command-Line: $optslen\n") if $opts{v}; #check for valid combination command-line arguments if ($opts{h} || !$opts{c} || ($optslen eq "0")) { print_usage(); exit; } # parse command-line arguments $port = $opts{c}; # COMx, where x is 1,2,3,4,... $ad9516 = $opts{a}; # Configure AD9516 $dac5682 = $opts{d}; # Configure DAC5682Z $cfg_dp = $opts{f}; # Configuration File $debug = $opts{v}; # Debug $led = $opts{l}; # LED $reset = $opts{s}; # SPI Reset $bram = $opts{b}; # BRAM File $addr = $opts{i}; # ILB Address $data = $opts{j}; # ILB Data $read = $opts{r}; # ILB Read Command $write = $opts{w}; # ILB Write Command $bram_nsram = $opts{g}; # Block Ram Enable ############################################################################### # Get COM Port Settings ############################################################################### $ctrlH{ 'port' } = $port; $ctrlH{ 'speed' } = $speed; $ctrlH{ 'bits' } = $bits; $ctrlH{ 'parity' } = $parity; $ctrlH{ 'stop' } = $stop; ############################################################################### # Stuff input options into a Hash: ############################################################################### $ctrlH{ 'ad9516' } = $ad9516; $ctrlH{ 'dac5682' } = $dac5682; $ctrlH{ 'led' } = $led; $ctrlH{ 'file' } = $cfg_dp; $ctrlH{ 'reset' } = $reset; $ctrlH{ 'bfile' } = $bram; $ctrlH{ 'ilb_addr' } = $addr; $ctrlH{ 'ilb_data' } = $data; $ctrlH{ 'debug' } = $debug; $ctrlH{ 'bram_nsram' } = $bram_nsram; ############################################################################### # Configure AD9516 ############################################################################### if ($ad9516) { $ctrl_rH = configAD9516(\%ctrlH); } ############################################################################### # Configure DAC5682 ############################################################################### if ($dac5682) { $ctrl_rH = configDAC5682(\%ctrlH); } ############################################################################### # Test RS-232 Interface: ############################################################################### if ($led) { $ctrl_rH = setLED(\%ctrlH); } ############################################################################### # Reset SPI Peripherals: ############################################################################### if ($reset) { $ctrl_rH = resetPeriphs(\%ctrlH); } ############################################################################### # Configure Data Path FPGA ############################################################################### if ($cfg_dp) { $ctrl_rH = configDPFPGA(\%ctrlH); } ############################################################################### # Send Block RAM Pattern to Data Path FPGA ############################################################################### if ($bram) { $ctrl_rH = setBRAM(\%ctrlH); } ############################################################################### # Enable Block RAM Pattern in Data Path FPGA ############################################################################### if ($bram_nsram) { $ctrl_rH = setBRAMEn(\%ctrlH); } ############################################################################### # Write Data Path FPGA Register: ############################################################################### if ($write) { print("Address: $addr\n") if $debug; print("Data: $data\n") if $debug; if ((defined $addr) && (defined $data)) { $ctrl_rH = writeRegDP($addr,$data,\%ctrlH); } else { print("ERROR: Please enter address and data!!!"); print_usage(); exit 1; } } ############################################################################### # Read Data Path FPGA Register: ############################################################################### if ($read) { print("Address: $addr\n") if $debug; if ((defined $addr)) { my ($ilb_rd_data) = readRegDP($addr,\%ctrlH); print("ILB Read 0x$ilb_rd_data from Address 0x$addr\n"); } else { print("ERROR: Please enter address!!!"); print_usage(); exit 1; } } exit; #****************************************************************** # Sub-routines #****************************************************************** sub dienice { my($errmsg) = @_; print"$errmsg\n"; exit; } sub print_usage { my ($usage); $usage = "\nUsage: $0 [-h] [-v] [-s] [-a] [-d] [-g] [-l ] [-f ] [-b ] [-r | -w] [-i ] [-j ]\n"; $usage .= "\n"; $usage .= "\t-h\t\tPrint Help.\n"; $usage .= "\t-v\t\tVerbose: Print Debug Information.\n"; $usage .= "\t-c \tCOM Port Settings: [PORT].\n"; $usage .= "\t-l \tSet LEDs On or Off (00 to FF, hexadecimal).\n"; $usage .= "\t-a\t\tConfigure AD9516.\n"; $usage .= "\t-d\t\tConfigure DAC5682Z.\n"; $usage .= "\t-s\t\tReset Peripherals.\n"; $usage .= "\t-f \tConfigure Data Path FPGA.\n"; $usage .= "\t-b \tBlock RAM User Pattern for Data Path FPGA.\n"; $usage .= "\t-i \tILB Address for Data Path FPGA.\n"; $usage .= "\t-j \tILB Data for Data Path FPGA.\n"; $usage .= "\t-r\t\tILB Read Command for Data Path FPGA.\n"; $usage .= "\t-w\t\tILB Write Command for Data Path FPGA.\n"; $usage .= "\t-g\t\tEnable Block RAM Patterns in Data Path FPGA.\n"; $usage .= "\n"; $usage .= "\tExample:\n"; $usage .= "\t\t$0 -c 4 -v -l 0 \n"; $usage .= "\t\t$0 -c 4 -v -a \n"; $usage .= "\t\t$0 -c 4 -v -d \n"; $usage .= "\t\t$0 -c 4 -v -f sig_dp_cfg.hex \n"; $usage .= "\n"; print($usage); return; } #*** # Writing Routines #*** sub resetPeriphs { ########################################################################## # Reset SPI Peripherals: # # The sub-routine resetPeriphs() will send the 1 byte containing the # desired reset value to the Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = resetPeriphs($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($reset) = $ctrlH{'reset'}; # LED Data (hexadecimal) my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Write Reset value in hex. ########################################################################## print("Set Reset Register to: 0x$reset\n"); my $cmdUser = sprintf "w 0001 $reset\r"; rs232write($cmdUser,$debug); usleep(100); print("Set Reset Register to: 0xFF\n"); my $cmdDflt = sprintf "w 0001 FF\r"; rs232write($cmdDflt,$debug); usleep(100); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub setLED { ########################################################################## # Set LED(s) On or Off: # # The sub-routine setLED() will send the 1 byte containing the # desired LED setting to the Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = setLED($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($led) = $ctrlH{'led'}; # LED Data (hexadecimal) my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Write LED value in hex. ########################################################################## my (@tmpA) = testhex($led); #,$debug); my ($led_hex8) = $tmpA[1]; my (@ledA) = split(//,$led_hex8); my ($led_76) = join("",@ledA[0..1]); my ($led_54) = join("",@ledA[2..3]); my ($led_32) = join("",@ledA[4..5]); my ($led_10) = join("",@ledA[6..7]); my $cmd = sprintf "w 0002 $led_10\r"; rs232write($cmd,$debug); usleep(100); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub writeRegAD9516 { ########################################################################## # Write AD9516 Register # # The sub-routine writeRegAD9516() will send the 5 bytes containing the # start FSM control bit, address, and write data bytes to the # Control FPGA via an RS-232 link. # # Usage: writeRegAD9516("00","00","99"); # ########################################################################## my ($addr1) = shift; my ($addr0) = shift; my ($wdata) = shift; my ($debug) = shift; # Create Address 0 Commands my $addr_a_cmd = sprintf "w 0038 $addr1\r"; rs232write($addr_a_cmd,$debug); usleep(5000); my $addr_b_cmd = sprintf "w 0039 $addr0\r"; rs232write($addr_b_cmd,$debug); usleep(5000); my $wr_data_cmd = sprintf "w 0037 $wdata\r"; rs232write($wr_data_cmd,$debug); usleep(5000); my $fsm_start_cmd = sprintf "w 0022 07\r"; # Toggle FSM Start Bit High rs232write($fsm_start_cmd,$debug); usleep(5000); $fsm_start_cmd = sprintf "w 0022 03\r"; # Toggle FSM Start Bit Low rs232write($fsm_start_cmd,$debug); usleep(5000); } sub readRegAD9516 { ########################################################################## # Read AD9516 Register # # The sub-routine readRegAD9516() will send the 4 bytes containing the # start FSM control bit, and address bytes to the # Control FPGA via an RS-232 link. # # Usage: $rdData = readRegAD9516("00","00"); # ########################################################################## my ($addr1) = shift; my ($addr0) = shift; my ($debug) = shift; # Create Address 0 Commands my $addr_a_cmd = sprintf "w 0038 $addr1\r"; rs232write($addr_a_cmd,$debug); usleep(1000); my $addr_b_cmd = sprintf "w 0039 $addr0\r"; rs232write($addr_b_cmd,$debug); usleep(1000); my $fsm_start_cmd = sprintf "w 0022 0F\r"; # Toggle FSM Start Bit High rs232write($fsm_start_cmd,$debug); usleep(1000); $fsm_start_cmd = sprintf "w 0022 0B\r"; # Toggle FSM Start Bit Low rs232write($fsm_start_cmd,$debug); usleep(1000); # Get AD9516 Read Data Status my ($ad9516_rd_cmd) = "r 0035"; my ($ad9516_dat) = readme($ad9516_rd_cmd,$debug); $ad9516_dat = readme($ad9516_rd_cmd,$debug); my ($rtrnRd) = sprintf "\rCTX>"; $rtrnRd =~ s/\r//g; $rtrnRd =~ s/\n//g; print("Return Read: $rtrnRd\n\n") if $debug; $ad9516_dat =~ s/[\r\n]//g; $ad9516_dat =~ s/CTX//g; $ad9516_dat =~ s/$rtrnRd//g; print("FSM Status: \n$ad9516_dat\n") if $debug; return $ad9516_dat; } sub startAD9516 { ########################################################################## # Start AD9516 Conversion # # The sub-routine startAD9516() will send the 1 bytes containing the # start FSM control bit, and read 2 bytes at a time containing the # AD9516 read data from the Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = startAD9516($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($ad9516) = $ctrlH{'ad9516'}; # Number of AD9516 Samples to Retrieve my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); print("Writing to AD9516.\n"); ########################################################################## # Write Address/Data Commands. ########################################################################## writeRegAD9516("00","00","BD"); #Serial Port Configuratio writeRegAD9516("00","00","99"); #Serial Port Configuratio writeRegAD9516("00","04","01"); #Read Back Control writeRegAD9516("00","10","4c"); #PFD and Charge Pump writeRegAD9516("00","11","01"); #R Counter writeRegAD9516("00","12","00"); #R Counter writeRegAD9516("00","13","00"); #A Counter writeRegAD9516("00","14","19"); #B Counter writeRegAD9516("00","15","00"); #B Counter writeRegAD9516("00","16","03"); #PLL Control 1 writeRegAD9516("00","17","00"); #PLL Control 2 writeRegAD9516("00","18","66"); #PLL Control 3 writeRegAD9516("00","19","00"); #PLL Control 4 writeRegAD9516("00","1a","00"); #PLL Control 5 writeRegAD9516("00","1b","00"); #PLL Control 6 writeRegAD9516("00","1c","07"); #PLL Control 7 writeRegAD9516("00","1d","00"); #PLL Control 8 writeRegAD9516("00","1e","00"); #PLL Control 9 writeRegAD9516("00","1f","00"); #PLL Readback writeRegAD9516("00","a0","01"); #OUT6 Delay Bypass writeRegAD9516("00","a1","00"); #OUT6 Delay Full-Scale writeRegAD9516("00","a2","00"); #OUT6 Delay Fraction writeRegAD9516("00","a3","01"); #OUT7 Delay Bypass writeRegAD9516("00","a4","00"); #OUT7 Delay Full-Scale writeRegAD9516("00","a5","00"); #OUT7 Delay Fraction writeRegAD9516("00","a6","01"); #OUT8 Delay Bypass writeRegAD9516("00","a7","00"); #OUT8 Delay Full-Scale writeRegAD9516("00","a8","00"); #OUT8 Delay Fraction writeRegAD9516("00","a9","01"); #OUT9 Delay Bypass writeRegAD9516("00","aa","00"); #OUT9 Delay Full-Scale writeRegAD9516("00","ab","00"); #OUT9 Delay Fraction writeRegAD9516("00","f0","0c"); #OUT0 writeRegAD9516("00","f1","04"); #OUT1 writeRegAD9516("00","f2","08"); #OUT2 writeRegAD9516("00","f3","08"); #OUT3 writeRegAD9516("00","f4","03"); #OUT4 writeRegAD9516("00","f5","03"); #OUT5 writeRegAD9516("01","40","02"); #OUT6 writeRegAD9516("01","41","02"); #OUT7 writeRegAD9516("01","42","01"); #OUT8 writeRegAD9516("01","43","02"); #OUT9 writeRegAD9516("01","90","00"); #Divider 0 (PECL) writeRegAD9516("01","91","40"); #Divider 0 (PECL) writeRegAD9516("01","92","01"); #Divider 0 (PECL) writeRegAD9516("01","93","11"); #Divider 1 (PECL) writeRegAD9516("01","94","40"); #Divider 1 (PECL) writeRegAD9516("01","95","01"); #Divider 1 (PECL) writeRegAD9516("01","96","00"); #Divider 2 (PECL) writeRegAD9516("01","97","00"); #Divider 2 (PECL) writeRegAD9516("01","98","00"); #Divider 2 (PECL) writeRegAD9516("01","99","00"); #Divider 3 (LVDS/CMOS) writeRegAD9516("01","9a","00"); #Divider 3 (LVDS/CMOS) writeRegAD9516("01","9b","00"); #Divider 3 (LVDS/CMOS) writeRegAD9516("01","9c","08"); #Divider 3 (LVDS/CMOS) writeRegAD9516("01","9d","01"); #Divider 3 (LVDS/CMOS) writeRegAD9516("01","9e","32"); #Divider 4 (LVDS/CMOS) writeRegAD9516("01","9f","00"); #Divider 4 (LVDS/CMOS) writeRegAD9516("01","a0","11"); #Divider 4 (LVDS/CMOS) writeRegAD9516("01","a1","28"); #Divider 4 (LVDS/CMOS) writeRegAD9516("01","a2","01"); #Divider 4 (LVDS/CMOS) writeRegAD9516("01","e0","02"); #VCO Divider writeRegAD9516("01","e1","01"); #Input CLKs writeRegAD9516("02","30","04"); #Power Down and Sync writeRegAD9516("02","32","01"); #Update All Registers print("Done Writing to AD9516.\n"); ########################################################################## # Get AD9516 Data (in Hex). ########################################################################## my $rdData = readRegAD9516("00","00"); print("Read: $rdData, from Address: 00\n"); # Get AD9516 FSM Status my ($ad9516_done_cmd) = "r 0023"; my ($ad9516_stat) = readme($ad9516_done_cmd); #,$debug); my ($ad9516_stat) = readme($ad9516_done_cmd); #,$debug); my ($rtrnRd) = sprintf "\rCTX>"; $rtrnRd =~ s/\r//g; $rtrnRd =~ s/\n//g; print("Return Read: $rtrnRd\n\n") if $debug; $ad9516_stat =~ s/[\r\n]//g; $ad9516_stat =~ s/CTX//g; $ad9516_stat =~ s/$rtrnRd//g; print("FSM Status: $ad9516_stat\n"); print("\n\n"); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub configAD9516 { ########################################################################## # Configure AD9516 # # The sub-routine configAD9516() will configure the AD9516 via the # Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = configAD9516($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Write data to Data Path FPGA: ########################################################################## $ctrl_rH = startAD9516(\%ctrlH); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub writeRegDAC5682 { ########################################################################## # Write DAC5682 Register # # The sub-routine writeRegDAC5682() will send the 4 bytes containing the # start FSM control bit, address, and write data bytes to the # Control FPGA via an RS-232 link. # # Usage: writeRegDAC5682("00","99"); # ########################################################################## my ($addr0) = shift; my ($wdata) = shift; my ($debug) = shift; # Create Address 0 Commands my $addr_b_cmd = sprintf "w 003B $addr0\r"; rs232write($addr_b_cmd,$debug); usleep(5000); my $wr_data_cmd = sprintf "w 003A $wdata\r"; rs232write($wr_data_cmd,$debug); usleep(5000); my $fsm_start_cmd = sprintf "w 0024 01\r"; # Toggle FSM Start Bit High rs232write($fsm_start_cmd,$debug); usleep(5000); $fsm_start_cmd = sprintf "w 0024 00\r"; # Toggle FSM Start Bit Low rs232write($fsm_start_cmd,$debug); usleep(5000); } sub readRegDAC5682 { ########################################################################## # Read DAC5682 Register # # The sub-routine readRegDAC5682() will send the 4 bytes containing the # start FSM control bit, and address bytes to the # Control FPGA via an RS-232 link. # # Usage: $rdData = readRegDAC5682("00","00"); # ########################################################################## my ($addr0) = shift; my ($debug) = shift; # Create Address 0 Commands my $addr_b_cmd = sprintf "w 003B $addr0\r"; rs232write($addr_b_cmd,$debug); usleep(1000); my $wr_data_cmd = sprintf "w 003A 00\r"; rs232write($wr_data_cmd,$debug); usleep(5000); my $fsm_start_cmd = sprintf "w 0024 03\r"; # Toggle FSM Start Bit High rs232write($fsm_start_cmd,$debug); usleep(1000); $fsm_start_cmd = sprintf "w 0024 02\r"; # Toggle FSM Start Bit Low rs232write($fsm_start_cmd,$debug); usleep(1000); # Get DAC5682 Read Data Status my ($dac5682_rd_cmd) = "r 0036"; my ($dac5682_dat) = readme($dac5682_rd_cmd,$debug); $dac5682_dat = readme($dac5682_rd_cmd,$debug); my ($rtrnRd) = sprintf "\rCTX>"; $rtrnRd =~ s/\r//g; $rtrnRd =~ s/\n//g; print("Return Read: $rtrnRd\n\n") if $debug; $dac5682_dat =~ s/[\r\n]//g; $dac5682_dat =~ s/CTX//g; $dac5682_dat =~ s/$rtrnRd//g; print("FSM Status: \n$dac5682_dat\n") if $debug; return $dac5682_dat; } sub startDAC5682 { ########################################################################## # Start DAC5682 Conversion # # The sub-routine startDAC5682() will send the 1 bytes containing the # start FSM control bit, and read 2 bytes at a time containing the # DAC5682 read data from the Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = startDAC5682($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($dac5682) = $ctrlH{'dac5682'}; # Number of DAC5682 Samples to Retrieve my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. my ($rdData); # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); print("Writing to DAC5682z.\n"); ########################################################################## # Write Address/Data Commands. ########################################################################## # Toggle Reset Low: my $rst_b_cmd = sprintf "w 0001 fd\r"; rs232write($rst_b_cmd,$debug); usleep(1000); # Toggle Reset High: $rst_b_cmd = sprintf "w 0001 ff\r"; rs232write($rst_b_cmd,$debug); usleep(1000); # Configure DAC5682 writeRegDAC5682("0e","e0",$debug); #SPI Serial Data Out and Channel B Offset (MSB) Control. writeRegDAC5682("05","92",$debug); #SPI Setup, Clock Divider, FIFO Offset Sync, and PLL/DLL Bypass Control. writeRegDAC5682("01","00",$debug); #DAC Delay, FIR Enable, Self Test, and FIFO Offset Control. writeRegDAC5682("02","80",$debug); #Two’s Comp Enable, Dual/Single DAC Mode, and FIR Mode Control. writeRegDAC5682("03","00",$debug); #DAC Offset Enable, A/B Swap, A equal B, SW Sync, and SW Sync Enable. writeRegDAC5682("06","ae",$debug); #Hold Sync, Sleep, Bias and PLL/DLL Sleep Control. writeRegDAC5682("07","ee",$debug); #Channel A and B Gain Control. writeRegDAC5682("08","00",$debug); #DLL Restart Control. Toggle bit 2 high then low. writeRegDAC5682("09","00",$debug); #PLL M/N Control. writeRegDAC5682("0a","00",$debug); #DLL Delay and Clock Control. writeRegDAC5682("0b","00",$debug); #PLL Loop Filter, VCO Divider, PLL Gain and Range Control. writeRegDAC5682("0c","00",$debug); #Offset Sync and Channel A Offset (MSB) Control. writeRegDAC5682("0d","00",$debug); #Channel A Offset (LSB) Control. writeRegDAC5682("0f","00",$debug); #Channel B Offset (LSB) Control. print("\n\n"); # Read Status Register $rdData = readRegDAC5682("00",$debug); print("Read: $rdData, from Address: 00\n"); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub configDAC5682 { ########################################################################## # Configure DAC5682 # # The sub-routine configDAC5682() will configure the DAC5682 via the # Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = configDAC5682($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Write data to Data Path FPGA: ########################################################################## $ctrl_rH = startDAC5682(\%ctrlH); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub getDPConfigFile { ########################################################################## # Get Input File: # # The sub-routine getDPConfigFile() will open the input file, which is either a # binary or text file and read its contents into an array. It will also # determine the file length. The following parameters are created # # * filedata: @vdataA # * fileLen: scalar(@vdataA) # # Usage: $xilinx_rH = getDPConfigFile(\%xilinxH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference Xilinx hash. my ($file) = $ctrlH{'file'}; # File Name my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. #-------------------------------------------------------------------------- # Open the text file, and read the results into an array for # sending to Data Path FPGA. Close file when done. #-------------------------------------------------------------------------- open(inF, "<", $file) or dienice ("$file open failed"); my (@vdataA) = ; close(inF); print("** Chomp input file line endings **\n") if $debug; my (@xconfigA); print scalar(@vdataA), "\n" if $debug; foreach my $j (@vdataA) { chomp($j); $j =~ s/\r//; if ($j eq "") { print("empty line 3\n") if $debug; } else { push(@xconfigA,$j); } print("$j\n") if $debug; } print scalar(@xconfigA), "\n" if $debug; push (@{ $ctrlH{ 'hexdata' } }, @xconfigA); #-------------------------------------------------------------------------- # Determine number of lines, and set beginning for loop index. #-------------------------------------------------------------------------- $ctrlH{ 'hexLen' } = scalar(@{ $ctrlH{ 'hexdata' } }); print("\n\n") if $debug; print("Total number of lines: $ctrlH{ 'hexLen' }\n") if $debug; print("\n\n") if $debug; ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub writeDPConfig { ########################################################################## # Write Data Path FPGA Configuration Data # # The sub-routine writeDPConfig() will send the 4 bytes containing the # Data Path FPGA Configuration Data to the Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = writeDPConfig($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($numWords) = $ctrlH{'hexLen'}; # Number of Configuration Words. my (@xconfigA); push (@xconfigA, @{ $ctrlH{ 'hexdata' } }); my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. my ($read_exp) = sprintf "\r00\rCTX>"; # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Start Sending Configuration Data: ########################################################################## # 1. Toggle PROG_B Low. print("1. Toggle PROG_B Low.\n"); my ($prog_b_lo_cmd) = sprintf("w 0066 00\r"); rs232write($prog_b_lo_cmd);#,$debug); # 2. Toggle PROG_B High. print("2. Toggle PROG_B High.\n"); my ($prog_b_hi_cmd) = sprintf("w 0066 01\r"); rs232write($prog_b_hi_cmd);#,$debug); # 3. Wait for INIT_B to go High. print("3. Wait for INIT_B to go High.\n"); my ($stat_rd_cmd) = sprintf "r 0065\r"; # init_b is bit 0 of read data.; my ($stat_rd_dat); my ($stat_rd_bin); my (@stat_rdA); my ($init_b) = 0; my ($timeout) = 32768; while (($init_b eq 0) && ($timeout > 0)) { rs232write($stat_rd_cmd,$debug); $stat_rd_dat = rs232read($read_exp); $stat_rd_dat =~ s/[\r|\n]//g; $stat_rd_dat =~ s/CTX//g; $stat_rd_dat =~ s/\x3e//g; # Convert INIT_B Status Data from Hex to Binary: $stat_rd_bin = hex2bin($stat_rd_dat); # Split the INIT_B Status Binary Data into an array of 1's and 0's: @stat_rdA = split(//,$stat_rd_bin); $init_b = $stat_rdA[7]; print("INIT_B: $init_b\n") if $debug; $timeout--; # decrement timeout; } if ($init_b eq 0) { print("INIT_B did not go High.!!!\n"); } else { print("INIT_B went High.!!!\n"); } # 4. Start Sending Data to FPGA. (xconfigA array should have 625,604 array elements) print("4. Start Sending Data to Data Path FPGA.\n"); my ($cnt) = $numWords; my ($cnt10k) = 10000; print("Number of Configuration Words: $cnt\n"); my ($m) = 0; for ($m = 0; $m < $numWords; $m++) { # a. Send Data. if ($xconfigA[$m] =~ /66aa9955/) { print("Found: 66aa9955 @ cnt: $cnt\n"); } ########################################################################## # Chop up Configuration 32-bit Write Data into 4 bytes. ########################################################################## # Pad MSB with zeros out to 32-bits or 8 hex digits: print("Data($cnt): $xconfigA[$m]\n") if $debug; my (@cfg_dataA) = testhex($xconfigA[$m]); #,$debug); # Grab ILB Data as 8 hex digits. my ($cfg_data_hex8) = $cfg_dataA[1]; # Split ILB Data into an array of nibbles: my (@cfg_data_hexA) = split(//,$cfg_data_hex8); # Concatenate Config Write Data into 4 bytes: my ($cfg_dat3_addr) = join("",@cfg_data_hexA[0..1]); my ($cfg_dat2_addr) = join("",@cfg_data_hexA[2..3]); my ($cfg_dat1_addr) = join("",@cfg_data_hexA[4..5]); my ($cfg_dat0_addr) = join("",@cfg_data_hexA[6..7]); ########################################################################## # Generate RS-232 Command Words: ########################################################################## # Configuration 32-bit Write Data Commands: my ($cfg_dat3_cmd) = sprintf("w 0061 $cfg_dat3_addr\r"); my ($cfg_dat2_cmd) = sprintf("w 0062 $cfg_dat2_addr\r"); my ($cfg_dat1_cmd) = sprintf("w 0063 $cfg_dat1_addr\r"); my ($cfg_dat0_cmd) = sprintf("w 0064 $cfg_dat0_addr\r"); print("CFG Command D3: $cfg_dat3_cmd\n") if $debug; print("CFG Command D2: $cfg_dat2_cmd\n") if $debug; print("CFG Command D1: $cfg_dat1_cmd\n") if $debug; print("CFG Command D0: $cfg_dat0_cmd\n") if $debug; rs232write($cfg_dat3_cmd);#,$debug); rs232write($cfg_dat2_cmd);#,$debug); rs232write($cfg_dat1_cmd);#,$debug); rs232write($cfg_dat0_cmd);#,$debug); # b. Set SDATA high. my ($sdat_b_hi_cmd) = sprintf("w 0060 01\r"); rs232write($sdat_b_hi_cmd);#,$debug); # c. Set SDATA low. my ($sdat_b_lo_cmd) = sprintf("w 0060 00\r"); rs232write($sdat_b_lo_cmd);#,$debug); # d. Wait for txfer_done to go high. usleep(500); # e. Repeat steps a-d until end of array. $cnt--; $cnt10k--; if ($cnt10k == 0) { $cnt10k = 10000; print("Configuration Word: $cnt\n"); } # if ($cnt10k == 9995) { # $m = $numWords; # } } # 5. Send clocks while waiting for INIT_B to go low. print("5. Wait for INIT_B to go Low.\n"); my ($timeout) = 32768; my ($sclk_b_hi_cmd) = sprintf("w 0060 02\r"); my ($sclk_b_lo_cmd) = sprintf("w 0060 00\r"); while (($init_b eq 1) && ($timeout > 0)) { # a. Set SCLKS high. rs232write($sclk_b_hi_cmd);#,$debug); # b. Set SCLKS low. rs232write($sclk_b_lo_cmd);#,$debug); # c. Wait for txfer_done to go high. usleep(500); # d. Check INIT_B to see if it's LOW. rs232write($stat_rd_cmd,$debug); $stat_rd_dat = rs232read($read_exp); $stat_rd_dat =~ s/[\r|\n]//g; $stat_rd_dat =~ s/CTX//g; $stat_rd_dat =~ s/\x3e//g; # Convert INIT_B Status Data from Hex to Binary: $stat_rd_bin = hex2bin($stat_rd_dat); # Split the INIT_B Status Binary Data into an array of 1's and 0's: @stat_rdA = split(//,$stat_rd_bin); $init_b = $stat_rdA[7]; print("INIT_B: $init_b\n") if $debug; # e. Repeat steps a-d a maximum of 32768 times. $timeout--; # decrement timeout } if ($timeout eq 0) { print("* Timeout reading DPCONFIG_status = 0x$stat_rd_dat\n"); } # 6. Check to see if DONE went high. print("6. Check to see if DONE went High.\n"); my ($done); # done is bit 1 in stat register. rs232write($stat_rd_cmd,$debug); $stat_rd_dat = rs232read($read_exp); $stat_rd_dat =~ s/[\r|\n]//g; $stat_rd_dat =~ s/CTX//g; $stat_rd_dat =~ s/\x3e//g; # Convert Status Data from Hex to Binary: $stat_rd_bin = hex2bin($stat_rd_dat); # Split the Status Binary Data into an array of 1's and 0's: @stat_rdA = split(//,$stat_rd_bin); $done = $stat_rdA[6]; $init_b = $stat_rdA[7]; print("DONE: $done\n") if $debug; print("INIT_B: $init_b\n") if $debug; if ($done eq 1) { # a. If DONE went high: print("Successful!!!\n"); # b. Set SCLKS high. rs232write($sclk_b_hi_cmd);#,$debug); # c. Set SCLKS low. rs232write($sclk_b_lo_cmd);#,$debug); } elsif ($init_b eq 0) { # a. If DONE is low, and INIT_B is low Configuration Failed. print("Failed CRC!!!\n"); } else { # a. If DONE is not high and INIT_B is high print warning that neither changed. print("Neither DONE nor INIT_B changed, status=0x$stat_rd_dat\n"); } ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub configDPFPGA { ########################################################################## # Configure Data Path FPGA # # The sub-routine configDPFPGA() will configure the Data Path FPGA via the # Control FPGA via an RS-232 link. # # Usage: $ctrl_rH = configDPFPGA($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Get Data Path FPGA Configuration File: ########################################################################## $ctrl_rH = getDPConfigFile(\%ctrlH); ########################################################################## # Write data to Data Path FPGA: ########################################################################## $ctrl_rH = writeDPConfig($ctrl_rH); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub getBRAMFile { ########################################################################## # Get Block RAM Pattern File: # # The sub-routine getBRAMFile() will open the Block RAM Pattern file # and read its contents into an array. It will also determine # the file length. The following parameters are created # # * fileData: @dataA # * fileLen: scalar(@dataA) # # Usage: $ctrl_rH = getBRAMFile(\%ctrlH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference Verilog hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Open the Verilog HDL file, and read the results into an array for # manipulating the data array. Strip new lines and carriage returns # from remove string array, and initialize for loop variables. Close file # when done. ########################################################################## open(inF, "<", $ctrlH{ 'bfile' }) or dienice ("$ctrlH{ 'bfile' } open failed"); my @dataA = ; close(inF); # Strip newlines foreach my $i (@dataA) { chomp($i); # Remove any \n line-feeds. $i =~ s/\r//g; # Remove any \r carriage-returns. } push (@{ $ctrlH{ 'bfileData' } }, @dataA); ########################################################################## # Determine number of lines ########################################################################## $ctrlH{ 'bfileLen' } = scalar(@{ $ctrlH{ 'bfileData' } }); print("\n\n") if $debug; print("Total number of lines: $ctrlH{ 'bfileLen' }\n") if $debug; print("\n\n") if $debug; ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub parseBRAMFile { ########################################################################## # Parse Block RAM Pattern File # # The sub-routine parseBRAMFile() will parse the input Block RAM Pattern File # and retrieve the following information: # # PatternLength=12288 # ReadStartAddressA=0 # ReadStopAddressA=95 # #begin # #end # # This sub-routine will also extract the actual pattern data into an # array for writing to the Data Path FPGA. # # Usage: $ctrl_rH = parseBRAMFile(\%ctrlH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Search through $file for keywords. ########################################################################## my ($i) = 0; my ($j) = 0; my ($patLen); my ($rdStartAddr_A); my ($rdStopAddr_A); my ($beginFound); my ($endFound); for ($i=0; $i < $ctrlH{ 'bfileLen' }; $i++) { if (${ $ctrlH{ 'bfileData' } }[$i] =~ m/PatternLength/) { $patLen = ${ $ctrlH{ 'bfileData' } }[$i]; $patLen =~ s/[\r\n]+$//; $patLen =~ s/.*PatternLength=//; print("Pattern Length: $patLen\n") if $debug; } if (${ $ctrlH{ 'bfileData' } }[$i] =~ m/ReadStartAddressA/) { $rdStartAddr_A = ${ $ctrlH{ 'bfileData' } }[$i]; $rdStartAddr_A =~ s/[\r\n]+$//; $rdStartAddr_A =~ s/.*ReadStartAddressA=//; print("Read Start Address: $rdStartAddr_A\n") if $debug; } if (${ $ctrlH{ 'bfileData' } }[$i] =~ m/ReadStopAddressA/) { $rdStopAddr_A = ${ $ctrlH{ 'bfileData' } }[$i]; $rdStopAddr_A =~ s/[\r\n]+$//; $rdStopAddr_A =~ s/.*ReadStopAddressA=//; print("Read Stop Address: $rdStopAddr_A\n") if $debug; } if (${ $ctrlH{ 'bfileData' } }[$i] =~ m/#begin/) { $beginFound = $i; print("Begin Line Number: $beginFound\n") if $debug; } if (${ $ctrlH{ 'bfileData' } }[$i] =~ m/#end/) { $endFound = $i; print("End Line Number: $endFound\n") if $debug; } } print("\n\n") if $debug; ########################################################################## # Search through $file for pattern data and store into a data array. ########################################################################## my (@bram_dataA); for ($j=($beginFound+1); $j < $endFound; $j++) { my ($tmp_data) = ${ $ctrlH{ 'bfileData' } }[$j]; $tmp_data =~ s/[\r\n]//; $tmp_data =~ s/[\r\n]//; #print("data: ${ $bramH{ 'fileData' } }[$j]\n"); #print("data: $tmp_data\n") if $debug; push(@bram_dataA, $tmp_data); } my ($bram_len) = scalar(@bram_dataA); $ctrlH{ 'patLen' } = $patLen; $ctrlH{ 'rdStartAddrA' } = $rdStartAddr_A; $ctrlH{ 'rdStopAddrA' } = $rdStopAddr_A; $ctrlH{ 'beginFound' } = $beginFound; $ctrlH{ 'endFound' } = $endFound; $ctrlH{ 'bramDataLen' } = $bram_len; push (@{ $ctrlH{ 'bramData' } }, @bram_dataA); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub writeBRAM { ########################################################################## # Send Block RAM Pattern to Data Path FPGA: # # The sub-routine writeBRAM() will send the Block RAM Pattern to the # Data Path FPGA via an RS-232 link. # # Usage: $ctrl_rH = writeBRAM($ctrlH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. my ($rdStartAddr_A) = $ctrlH{'rdStartAddrA'}; my ($rdStopAddr_A) = $ctrlH{'rdStopAddrA'}; my ($bram_len) = $ctrlH{'bramDataLen'}; my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Write Pattern Data to Data Path FPGA: ########################################################################## # Usage: $rdData = readRegDP($ilb_addr,$debug); # Usage: writeRegDP($ilb_addr, $ilb_data, $debug); # Set IDELAY_CTRL Reset Register to Default State: writeRegDP("010a", "ff", \%ctrlH); # Set IDELAY_CTRL Reset Register to Default State: writeRegDP("010a", "0", \%ctrlH); # Set Block RAM Write Control: writeRegDP("0380", "01ff", \%ctrlH); # Set Block RAM Read Control: writeRegDP("038c", "0", \%ctrlH); my ($j) = 0; for ($j=0; $j<$bram_len; $j+=4) { # Set Block RAM Write Address: my ($bramA) = $j/4; my ($bramA_h) = jww_dec2hex($bramA); writeRegDP("0382", $bramA_h, \%ctrlH); # Set Block RAM Write Data 0: my ($bramD0) = ${ $ctrlH{ 'bramData' } }[$j+3]; my ($bramD1) = ${ $ctrlH{ 'bramData' } }[$j+2]; my ($bramD2) = ${ $ctrlH{ 'bramData' } }[$j+1]; my ($bramD3) = ${ $ctrlH{ 'bramData' } }[$j+0]; writeRegDP("0384", $bramD0, \%ctrlH); writeRegDP("0386", $bramD1, \%ctrlH); writeRegDP("0388", $bramD2, \%ctrlH); writeRegDP("038a", $bramD3, \%ctrlH); } # Set Block RAM Write Control: writeRegDP("0380", "0", \%ctrlH); # Set Block RAM Read Start Address A: my ($rdStartAddr_A_h) = jww_dec2hex($rdStartAddr_A); writeRegDP("038e", $rdStartAddr_A_h, \%ctrlH); # Set Block RAM Read Stop Address A: my ($rdStopAddr_A_h) = jww_dec2hex($rdStopAddr_A); writeRegDP("0390", $rdStopAddr_A_h, \%ctrlH); # Set Block RAM Read Control: writeRegDP("038c", "1", \%ctrlH); # Set RAM/nPRBS mode to RAM: writeRegDP("0400", "1", \%ctrlH); # Set BRAM/nSRAM mode to SRAM: writeRegDP("040e", "1", \%ctrlH); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub setBRAM { ########################################################################## # Send Block RAM Pattern to Data Path FPGA: # # The sub-routine setBRAM() will send the Block RAM Pattern to the # Data Path FPGA via an RS-232 link. # # Usage: $ctrl_rH = setBRAM($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Get Block RAM Patter File: ########################################################################## $ctrl_rH = getBRAMFile(\%ctrlH); ########################################################################## # Parse Block RAM Pattern File: ########################################################################## $ctrl_rH = parseBRAMFile($ctrl_rH); ########################################################################## # Write data to Data Path FPGA: ########################################################################## $ctrl_rH = writeBRAM($ctrl_rH); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub writeBRAMEn { ########################################################################## # Enable Block RAM Pattern in Data Path FPGA: # # The sub-routine writeBRAM() will send the Block RAM Pattern to the # Data Path FPGA via an RS-232 link. # # Usage: $ctrl_rH = writeBRAMEn($ctrlH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. # my ($bfile) = $ctrlH{'bfile'}; my ($bram_nsram) = $ctrlH{'bram_nsram'}; my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Write Pattern Data to Data Path FPGA: ########################################################################## if ($bram_nsram eq "1") { # Set Reset Register: Reset Error Inj, FIFO, and PRWS Modules: writeRegDP("0002", "04", \%ctrlH); # Set Reset Register to Default State: writeRegDP("0002", "f4", \%ctrlH); # Set Block RAM Pattern: # my ($bramFile_cmd) = sprintf "16 pattern\\$bfile\r\n"; # Set Block RAM Read Control: writeRegDP("038c", "1", \%ctrlH); # Set BRAM/nSRAM mode to SRAM: writeRegDP("0402", "1", \%ctrlH); # Toggle Wave Enable: writeRegDP("0408", "0", \%ctrlH); writeRegDP("0408", "1", \%ctrlH); } ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub setBRAMEn { ########################################################################## # Enable Block RAM Pattern in Data Path FPGA: # # The sub-routine setBRAMEn() will enable the Block RAM Pattern in the # Data Path FPGA via an RS-232 link. # # Usage: $ctrl_rH = setBRAMEn($ctrl_rH); # ########################################################################## my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. ########################################################################## # Write data to Data Path FPGA: ########################################################################## $ctrl_rH = writeBRAMEn(\%ctrlH); ########################################################################## # # Return data to user # ########################################################################## return \%ctrlH; } sub readRegDP { ########################################################################## # Read Data Path FPGA: # # The sub-routine readRegDP() will send the 16-bit address to and # retrieve 32-bit data from the Control FPGA via an RS-232 link. # # The 16-bit address is divided into an MSB byte and an LSB byte: # # addr[15:8] ilb_rdwr1_addr 9'h040 # addr[7:0] ilb_rdwr0_addr 9'h041 # # The 32-bit Read data is divided into 4 bytes: # # data[31:24] ilb_rdd3_addr 9'h047 # data[23:16] ilb_rdd2_addr 9'h048 # data[15:8] ilb_rdd1_addr 9'h049 # datat[7:0] ilb_rdd0_addr 9'h04A # # After the 6 address/data bytes are sent to the Control FPGA, this # routine will toggle the ILB Start Bit: # # start_ilb ilb_ctrl_addr 9'h046 # # This routine will then read the transfer done flag to determine if # the transaction was successful. If the flag is high, then # it will print nothing. If the flag is low, then it will print # the following error message: # # "ERROR: Transfer Incomplete" # # Usage: $rdData = readRegDP($ilb_addr,$debug); # ########################################################################## my ($ilb_addr) = shift; my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Chop up ILB 16-bit Address into 2 bytes. ########################################################################## # Pad MSB with zeros out to 32-bits or 8 hex digits: my (@ilb_addrA) = testhex($ilb_addr); #,$debug); # Grab ILB Address as 8 hex digits. my ($ilb_addr_hex8) = $ilb_addrA[1]; # Split ILB Address into an array of nibbles: my (@ilb_addr_hexA) = split(//,$ilb_addr_hex8); # Concatenate ILB Address into 2 bytes: my ($ilb_rdwr1_addr) = join("",@ilb_addr_hexA[4..5]); my ($ilb_rdwr0_addr) = join("",@ilb_addr_hexA[6..7]); ########################################################################## # Generate RS-232 Command Words: ########################################################################## # ILB 16-bit Address Commands: my ($ilb_rdwr1_cmd) = sprintf("w 0040 $ilb_rdwr1_addr\r"); my ($ilb_rdwr0_cmd) = sprintf("w 0041 $ilb_rdwr0_addr\r"); # ILB 32-bit Read Data Commands: my ($ilb_rdd3_cmd) = sprintf("r 0047\r"); my ($ilb_rdd2_cmd) = sprintf("r 0048\r"); my ($ilb_rdd1_cmd) = sprintf("r 0049\r"); my ($ilb_rdd0_cmd) = sprintf("r 004A\r"); # ILB Control Commands: my ($ilb_ctrlH_cmd) = sprintf("w 0046 07\r"); my ($ilb_ctrlL_cmd) = sprintf("w 0046 06\r"); # ILB Status Commands: my ($ilb_stat_cmd) = sprintf("r 004b\r"); ########################################################################## # Send RS-232 Write Commands: ########################################################################## # Send ILB 16-bit Address: rs232write($ilb_rdwr1_cmd);#,$debug); rs232write($ilb_rdwr0_cmd);#,$debug); # Send ILB Control Commands: rs232write($ilb_ctrlH_cmd);#,$debug); rs232write($ilb_ctrlL_cmd);#,$debug); # Send ILB 32-bit Data: my ($rd3) = readme($ilb_rdd3_cmd, $debug); my ($rd2) = readme($ilb_rdd2_cmd, $debug); my ($rd1) = readme($ilb_rdd1_cmd, $debug); my ($rd0) = readme($ilb_rdd0_cmd, $debug); my (@rdA); push(@rdA, $rd3); push(@rdA, $rd2); push(@rdA, $rd1); push(@rdA, $rd0); my ($rdData) = join("",@rdA); ########################################################################## # # Return data to user # ########################################################################## return ($rdData); } sub writeRegDP { ########################################################################## # Write Data Path FPGA Register: # # The sub-routine writeRegDP() will send the 16-bit address and # 32-bit data to the Control FPGA via an RS-232 link. # # The 16-bit address is divided into an MSB byte and an LSB byte: # # addr[15:8] ilb_rdwr1_addr 9'h040 # addr[7:0] ilb_rdwr0_addr 9'h041 # # The 32-bit write data is divided into 4 bytes: # # data[31:24] ilb_wrd3_addr 9'h042 # data[23:16] ilb_wrd2_addr 9'h043 # data[15:8] ilb_wrd1_addr 9'h044 # datat[7:0] ilb_wrd0_addr 9'h045 # # After the 6 address/data bytes are sent to the Control FPGA, this # routine will toggle the ILB Start Bit: # # start_ilb ilb_ctrl_addr 9'h046 # # This routine will then read the transfer done flag to determine if # the transaction was successful. If the flag is high, then # it will print nothing. If the flag is low, then it will print # the following error message: # # "ERROR: Transfer Incomplete" # # Usage: writeRegDP($ilb_addr, $ilb_data, $debug); # ########################################################################## my ($ilb_addr) = shift; my ($ilb_data) = shift; my ($ctrl_rH) = shift; # Read in user's variable. my (%ctrlH) = %{ $ctrl_rH }; # De-reference error rate hash. my ($port) = $ctrlH{'port'}; # COM3 my ($speed) = $ctrlH{'speed'}; # 115200 my ($bits) = $ctrlH{'bits'}; # 8 my ($parity) = $ctrlH{'parity'}; # N my ($stop) = $ctrlH{'stop'}; # 1 my ($debug) = $ctrlH{'debug'}; # Print out Debug Info. # Initialize COM Port: my $comfh = JWinit($port,$speed,$bits,$parity,$stop,$debug); ########################################################################## # Chop up ILB 16-bit Address into 2 bytes. ########################################################################## # Pad MSB with zeros out to 32-bits or 8 hex digits: my (@ilb_addrA) = testhex($ilb_addr); #,$debug); # Grab ILB Address as 8 hex digits. my ($ilb_addr_hex8) = $ilb_addrA[1]; # Split ILB Address into an array of nibbles: my (@ilb_addr_hexA) = split(//,$ilb_addr_hex8); # Concatenate ILB Address into 2 bytes: my ($ilb_rdwr1_addr) = join("",@ilb_addr_hexA[4..5]); my ($ilb_rdwr0_addr) = join("",@ilb_addr_hexA[6..7]); ########################################################################## # Chop up ILB 32-bit Write Data into 4 bytes. ########################################################################## # Pad MSB with zeros out to 32-bits or 8 hex digits: my (@ilb_dataA) = testhex($ilb_data); #,$debug); # Grab ILB Data as 8 hex digits. my ($ilb_data_hex8) = $ilb_dataA[1]; # Split ILB Data into an array of nibbles: my (@ilb_data_hexA) = split(//,$ilb_data_hex8); # Concatenate ILB Write Data into 4 bytes: my ($ilb_wrd3_addr) = join("",@ilb_data_hexA[0..1]); my ($ilb_wrd2_addr) = join("",@ilb_data_hexA[2..3]); my ($ilb_wrd1_addr) = join("",@ilb_data_hexA[4..5]); my ($ilb_wrd0_addr) = join("",@ilb_data_hexA[6..7]); ########################################################################## # Generate RS-232 Command Words: ########################################################################## print("Writing 0x$ilb_data_hex8 to Address 0x$ilb_addr_hex8\n"); # ILB 16-bit Address Commands: my ($ilb_rdwr1_cmd) = sprintf("w 0040 $ilb_rdwr1_addr\r"); my ($ilb_rdwr0_cmd) = sprintf("w 0041 $ilb_rdwr0_addr\r"); # ILB 32-bit Write Data Commands: my ($ilb_wrd3_cmd) = sprintf("w 0042 $ilb_wrd3_addr\r"); my ($ilb_wrd2_cmd) = sprintf("w 0043 $ilb_wrd2_addr\r"); my ($ilb_wrd1_cmd) = sprintf("w 0044 $ilb_wrd1_addr\r"); my ($ilb_wrd0_cmd) = sprintf("w 0045 $ilb_wrd0_addr\r"); # ILB Control Commands: my ($ilb_ctrlH_cmd) = sprintf("w 0046 05\r"); my ($ilb_ctrlL_cmd) = sprintf("w 0046 04\r"); # ILB Status Commands: my ($ilb_stat_cmd) = sprintf("r 004b\r"); ########################################################################## # Send RS-232 Write Commands: ########################################################################## # Send ILB 16-bit Address: rs232write($ilb_rdwr1_cmd);#,$debug); usleep(5000); rs232write($ilb_rdwr0_cmd);#,$debug); usleep(5000); # Send ILB 32-bit Data: rs232write($ilb_wrd3_cmd);#,$debug); usleep(5000); rs232write($ilb_wrd2_cmd);#,$debug); usleep(5000); rs232write($ilb_wrd1_cmd);#,$debug); usleep(5000); rs232write($ilb_wrd0_cmd);#,$debug); usleep(5000); # Send ILB Control Commands: rs232write($ilb_ctrlH_cmd);#,$debug); usleep(5000); rs232write($ilb_ctrlL_cmd);#,$debug); usleep(5000); } #*** # Math Routines #*** sub hex2bin { my $hex = shift; my $binary; my %h2b = (0 => "0000", 1 => "0001", 2 => "0010", 3 => "0011", 4 => "0100", 5 => "0101", 6 => "0110", 7 => "0111", 8 => "1000", 9 => "1001", a => "1010", b => "1011", c => "1100", d => "1101", e => "1110", f => "1111", ); ($binary = $hex) =~ s/(.)/$h2b{lc $1}/g; return ($binary); } sub jww_dec2hex($) { my( $dec ) = shift; #return sprintf("%lx", $dec ); return sprintf("%x", $dec ); } sub testhex { ########################################################################## # Test Hexadecimal Values: # # The sub-routine testhex() will receive a single # hexadecimal value. If the hexadecimal value is less # than 8 digits, then testhex() will prepend the # appropriate number of zeros in order to provide a # complete 32-bit hexadecimal value. An error flag is # also provided to determine if the hex value is more # than 8 digits. # # @hexOut = (orig, hex8, len, hflag); # # Usage: my (@hexOut) = testhex($hexIn,$debug); # ########################################################################## my ($hexIn) = shift; my ($debug) = shift; my (@hexInA) = split(//,$hexIn); my ($hexInALen) = scalar(@hexInA); print("Hex In: $hexIn\n") if ($debug); print("Hex Length In: $hexInALen\n") if ($debug); my (@hexOut); my ($i); my ($hexDiff) = 8-$hexInALen; my ($hFlag) = 0; if ($hexDiff == 0) { print("hex length is 8\n") if ($debug); push(@hexOut, $hexIn); push(@hexOut, $hexIn); push(@hexOut, $hexInALen); push(@hexOut, $hFlag); } elsif ($hexDiff > 0) { for ($i=0; $i<$hexDiff; $i++) { unshift(@hexInA,0); } push(@hexOut, $hexIn); push(@hexOut, join("", @hexInA)); push(@hexOut, $hexInALen); push(@hexOut, $hFlag); print("hex length is $hexInALen, add $hexDiff zeros to pad to 8\n") if ($debug); print("New Hex: $hexOut[1]\n") if ($debug); } else { $hFlag = 1; push(@hexOut, $hexIn); push(@hexOut, $hexIn); push(@hexOut, $hexInALen); push(@hexOut, $hFlag); print("hex length is: $hexInALen\n"); } foreach my $i (@hexOut) { print("$i\n") if ($debug); } return(@hexOut); } #*** # RS-232 Stuff #*** # Read the first line from the socket to determine which # com port to connect to. Form should be: "com1,9600,8N1" # If you put a trailing ",1" like this "com1,9600,8N1,1" # The server will go into debug mode. # sub JWinit { my $comport= shift; my $speed= shift; my $bits= shift; my $parity= shift; my $stop= shift; my $debug= shift; ########################################################################## # Setup COM Port: ########################################################################## my $port = $comport-1; my $sys = $^O; print("System: $sys\n") if $debug; my ($strport) = ""; if ($sys =~ /cygwin/i) { $strport = "/dev/ttyS$port"; #print("I think I am Cygwin\n"); } else { $strport = "/dev/ttyUSB$port"; #print("I think I am Linux\n"); } $bits="cs" . $bits; my $popts=""; $popts = paren_opts(uc($parity)); $stop=($stop eq "2")? "cstopb" : "-cstopb"; my $rval=system("stty -F $strport -echo speed $speed $bits $popts $stop >/dev/null 2>&1"); if (defined $comfh) { print("COM Port already opened.\n") if $debug; return($comfh); } else { $comfh = new FileHandle("+<$strport") or die("Could not open com port: $port: $!\n"); #open($comfh,"+<$strport") or die("Could not open com port: $port: $!\n"); print "Opened port $strport $speed $bits,$parity,$stop\n"; #Set filehandles to autoflush return($comfh); } } sub paren_opts { my ($parity) = shift; # $popts = paren_opts(uc($parity)); if ($parity eq "E") { return " parenb -parodd"; } elsif ($parity eq "O") { return " parenb parodd"; } else { return "-parenb -parodd"; } } # Write slowly to the COM port, one character at # a time, reading it's echo, so PPG's runloop has time # to keep up with the incoming stream # sub rs232write { my $wrdata = shift; my $debug = shift; print "Write Data: $wrdata" if ($debug); slowwrite($wrdata,$debug); usleep(4000); } sub slowwrite { my $outstr=shift; my $debug = shift; my $j=0; print "writing to com port: $outstr\n" if $debug; for ($j=0; $jautoflush(1); } sub fixendings { my $instr=shift; if ($instr =~ m/[\r\n]/) { #print("instruction has newline or carriage return\n"); $instr=~s/[\r\n]+$//; # remove Return, newline and the trailer } return($instr . "\r"); # add the return and newline to the $instr } ########################################################## # RS-232 Read Sub-Routines: ########################################################## sub readme { ########################################################################## # Read Register: # # Usage: $rd_data = readme($cmd, $debug); # ########################################################################## my ($cmd) = shift; my ($debug) = shift; # Add carriage return to incoming command: my ($buffer) = sprintf "$cmd\r"; rs232write($buffer,$debug); my ($rtrnRd) = sprintf "\r01\rCTX>"; my ($rd_data) = rs232read($rtrnRd); $rd_data =~ s/[\r\n]//; $rd_data =~ s/CTX//; $rd_data =~ s/\x3e//; print("Read Data Return: \n$rd_data\n") if $debug; ########################################################################## # Return data to user ########################################################################## return ($rd_data); } # Read slowly to the COM port, one character at # a time, reading it's echo, so Hydra's runloop has time # to keep up with the incoming stream # sub rs232read { my $expected=shift; #my ($rtrn) = slowread(fixendingsRd($expected)); my ($rtrn) = slowread($expected); # usleep(4000); return($rtrn); } sub slowread { my $outstr=shift; my $j=0; my @rtrnA; #print "Expected String Length from com port: $outstr\n"; for ($j=0; $j