annotate pygar-benchmarks/setup/run-sim.bmark @ 69:5c963ab14143 pygar svn.70

[svn r70] added an attempt at multi-fileing
author punk
date Wed, 12 May 2010 00:07:40 -0400
parents 0ede0715dbd6
children
rev   line source
rlm@67 1 #!/usr/bin/env perl
rlm@67 2 # -*- perl -*-
rlm@67 3
rlm@67 4 use strict;
rlm@67 5 use warnings;
rlm@67 6 use Getopt::Long qw(:config no_auto_abbrev no_ignore_case pass_through);
rlm@67 7 use IO::Pty;
rlm@67 8
rlm@67 9 #
rlm@67 10 # Turn on warnings
rlm@67 11 #
rlm@67 12 $^W = 1;
rlm@67 13
rlm@67 14 ##
rlm@67 15 ## Benchmark run script
rlm@67 16 ##
rlm@67 17
rlm@67 18 sub ExecModel($);
rlm@67 19 sub Exec($$);
rlm@67 20 sub CompareOutput();
rlm@67 21 sub ReadConfig($$);
rlm@67 22
rlm@67 23
rlm@67 24 #############################################################################
rlm@67 25 #############################################################################
rlm@67 26 ##
rlm@67 27 ## Start by figuring out the model location and type.
rlm@67 28 ##
rlm@67 29 #############################################################################
rlm@67 30 #############################################################################
rlm@67 31
rlm@67 32 my %config;
rlm@67 33
rlm@67 34 ReadConfig("config/env.sh", 1);
rlm@67 35 ReadConfig("$config{modelDir}/config/env.sh", 1);
rlm@67 36 ReadConfig("$config{modelDir}/config/signature.sh", 0);
rlm@67 37
rlm@67 38 ##
rlm@67 39 ## Pseudo-enumeration of possible model types
rlm@67 40 ##
rlm@67 41 my $MODEL_NONE = 0;
rlm@67 42 my $MODEL_FPGA = 1; # Model runs on FPGA hardware
rlm@67 43 my $MODEL_BLUESIM = 2; # Bluesim
rlm@67 44 my $MODEL_VSIM = 3; # Verilog simulator
rlm@67 45
rlm@67 46 my $mType = $MODEL_NONE;
rlm@67 47
rlm@67 48
rlm@67 49 #############################################################################
rlm@67 50 #############################################################################
rlm@67 51 ##
rlm@67 52 ## Process command line arguments
rlm@67 53 ##
rlm@67 54 #############################################################################
rlm@67 55 #############################################################################
rlm@67 56
rlm@67 57 my $help = 0;
rlm@67 58 my $onlyCompare = 0;
rlm@67 59 my $noCompare = 0;
rlm@67 60 my $forceLoad = 0;
rlm@67 61 my $gdb = 0;
rlm@67 62 my $noProgram = 0;
rlm@67 63 my $noReserve = 0;
rlm@67 64 my $funcpPrefix = "";
rlm@67 65 my $funcpSuffix = "";
rlm@67 66 my $noshowfp = 0;
rlm@67 67 my $printCycle = undef;
rlm@67 68 my $showfp = undef;
rlm@67 69 my $bluesimCmd = undef;
rlm@67 70 my $vcdStart = undef;
rlm@67 71 my $vcdCycles = 20000;
rlm@67 72 my $m5run = 0;
rlm@67 73
rlm@67 74 my $status = GetOptions("help!" => \$help,
rlm@67 75 "gdb!" => \$gdb,
rlm@67 76 "noprogram!" => \$noProgram,
rlm@67 77 "noreserve!" => \$noReserve,
rlm@67 78 "force-load!" => \$forceLoad,
rlm@67 79 "funcp-prefix=s" => \$funcpPrefix,
rlm@67 80 "funcp-suffix=s" => \$funcpSuffix,
rlm@67 81 "noshowfp!" => \$noshowfp,
rlm@67 82 "onlycompare!" => \$onlyCompare,
rlm@67 83 "nocompare!" => \$noCompare,
rlm@67 84 "pc=s" => \$printCycle,
rlm@67 85 "showfp:s" => \$showfp,
rlm@67 86 "bluesim=s" => \$bluesimCmd,
rlm@67 87 "vcdstart=i" => \$vcdStart,
rlm@67 88 "vcdcycles=i" => \$vcdCycles,
rlm@67 89 "m5!" => \$m5run,
rlm@67 90 );
rlm@67 91
rlm@67 92 # Put quotation marks back on arguments that have spaces since they will be
rlm@67 93 # passed through a shell once more.
rlm@67 94 foreach my $i ( 0 .. $#ARGV ) {
rlm@67 95 if (($ARGV[$i] =~ /\s/) && ! ($ARGV[$i] =~ /['"]$/)) {
rlm@67 96 $ARGV[$i] = '"' . $ARGV[$i] . '"';
rlm@67 97 }
rlm@67 98 }
rlm@67 99
rlm@67 100 if ($onlyCompare != 0) {
rlm@67 101 exit(CompareOutput());
rlm@67 102 }
rlm@67 103
rlm@67 104 if ($m5run != 0) {
rlm@67 105 $mType = $MODEL_NONE;
rlm@67 106 }
rlm@67 107 elsif (-f "$config{modelDir}/$config{model}_hw.errinfo") {
rlm@67 108 $mType = $MODEL_FPGA;
rlm@67 109 }
rlm@67 110 elsif (-f "$config{modelDir}/$config{model}_hw.exe") {
rlm@67 111 $mType = $MODEL_BLUESIM;
rlm@67 112 }
rlm@67 113 elsif (-f "$config{modelDir}/$config{model}_hw.vexe") {
rlm@67 114 $mType = $MODEL_VSIM;
rlm@67 115 }
rlm@67 116 else {
rlm@67 117 die("Can't determine model type");
rlm@67 118 }
rlm@67 119
rlm@67 120 if ($help || ! $status) {
rlm@67 121 print STDERR "\nArguments:\n";
rlm@67 122 print STDERR " [--gdb] Invokes the software side in gdb\n";
rlm@67 123 print STDERR " [--noprogram] Skips the FPGA load and reservation steps\n";
rlm@67 124 print STDERR " [--noreserve] Skips the FPGA reservation steps\n";
rlm@67 125 print STDERR " [--funcp-prefix=\"<prefix>\"]\n";
rlm@67 126 print STDERR " Prepend prefix to HAsim's --funcp argument\n";
rlm@67 127 print STDERR " [--funcp-suffix=\"<suffix>\"]\n";
rlm@67 128 print STDERR " Append suffix to HAsim's --funcp argument\n";
rlm@67 129 print STDERR " [--onlycompare] Only compare output files (without running)\n";
rlm@67 130 print STDERR " [--nocompare] Skip comparison of output files\n";
rlm@67 131 print STDERR " [--m5] Run workload in m5 without HAsim\n";
rlm@67 132
rlm@67 133 if ($mType == $MODEL_FPGA) {
rlm@67 134 print STDERR " [--force-load] Load a bitfile to the FPGA even if it has errors\n";
rlm@67 135 }
rlm@67 136
rlm@67 137 if ($mType == $MODEL_BLUESIM) {
rlm@67 138 print STDERR " [--vcdstart=<cycle>] Generate VCD dump for wave viewer (e.g. gtkwave)\n";
rlm@67 139 print STDERR " [--vcdcycles=<cycles>] VCD dump length (default = 20000)\n";
rlm@67 140 }
rlm@67 141
rlm@67 142 if ($config{isHybridModel}) {
rlm@67 143 my $cmd = "$config{modelDir}/$config{model} --help-run-append";
rlm@67 144 system($cmd);
rlm@67 145 }
rlm@67 146
rlm@67 147 exit(1);
rlm@67 148 }
rlm@67 149
rlm@67 150 #############################################################################
rlm@67 151 #############################################################################
rlm@67 152 ##
rlm@67 153 ## Adjust model arguments
rlm@67 154 ##
rlm@67 155 #############################################################################
rlm@67 156 #############################################################################
rlm@67 157
rlm@67 158 # Show front panel?
rlm@67 159 if ($noshowfp) {
rlm@67 160 $showfp = 'none';
rlm@67 161 }
rlm@67 162 elsif (defined($showfp)) {
rlm@67 163 # Specified on the run command line
rlm@67 164 $showfp = 'gui' if ($showfp eq '');
rlm@67 165 }
rlm@67 166 elsif ($config{feeder} eq 'none') {
rlm@67 167 # For null feeder default to showing LEDs on stdout
rlm@67 168 $showfp = 'stdout';
rlm@67 169 }
rlm@67 170 else {
rlm@67 171 # Other models have heartbeats
rlm@67 172 $showfp = 'none';
rlm@67 173 }
rlm@67 174
rlm@67 175 my $feedFlags = "${funcpPrefix} $config{feedFlags} ${funcpSuffix}";
rlm@67 176
rlm@67 177 if ($config{feeder} eq 'm5') {
rlm@67 178 # Tell m5 to be quiet and not to enable the remote gdb port. Under netbatch
rlm@67 179 # it appears there are sometimes attempts to connect to the port, which
rlm@67 180 # stops simulation.
rlm@67 181 $feedFlags = "--quiet --remote-gdb-port=0 ${feedFlags}";
rlm@67 182 }
rlm@67 183
rlm@67 184 my $cmd;
rlm@67 185
rlm@67 186 if ($m5run == 0) {
rlm@67 187 # Normal run
rlm@67 188 $cmd = "$config{modelDir}/$config{model} --modeldir=$config{modelDir} --workload=$config{workload} --showfp=${showfp} --funcp=\"${feedFlags}\" $config{genFlags}";
rlm@67 189 foreach my $c (@ARGV) {
rlm@67 190 $cmd .= " $c";
rlm@67 191 }
rlm@67 192
rlm@67 193 if (defined($printCycle)) {
rlm@67 194 $cmd .= " --pc=${printCycle}";
rlm@67 195 }
rlm@67 196 }
rlm@67 197 else {
rlm@67 198 if ($config{feeder} ne 'm5') {
rlm@67 199 die("This workload does not use m5");
rlm@67 200 }
rlm@67 201
rlm@67 202 # Running inside m5 without HAsim
rlm@67 203 my $m5cmd;
rlm@67 204 if (exists($ENV{M5BIN})) {
rlm@67 205 $m5cmd = $ENV{M5BIN};
rlm@67 206 }
rlm@67 207 else {
rlm@67 208 my $m5bin = "platform/m5/build/ALPHA_SE/m5." . ($gdb ? "debug" : "opt");
rlm@67 209 $m5cmd = `awb-resolver ${m5bin}`;
rlm@67 210 chomp($m5cmd);
rlm@67 211 die("Failed to find $m5bin") if ($m5cmd eq '');
rlm@67 212 }
rlm@67 213
rlm@67 214 $cmd = "${m5cmd} ${feedFlags}";
rlm@67 215
rlm@67 216 # Drop --hasim-sim
rlm@67 217 $cmd =~ s/--hasim-sim //;
rlm@67 218 # Drop escaping of quotes
rlm@67 219 $cmd =~ s/\\"/"/g;
rlm@67 220
rlm@67 221 $noProgram = 1;
rlm@67 222 }
rlm@67 223
rlm@67 224 #
rlm@67 225 # Bluesim arguments
rlm@67 226 #
rlm@67 227
rlm@67 228 # Generate dump.vcd for wave viewer (e.g. gtkwave)?
rlm@67 229 if (defined($vcdStart)) {
rlm@67 230 my $vcdCmd = "sim vcd on; sim step $vcdCycles; sim stop";
rlm@67 231 if ($vcdStart > 0) {
rlm@67 232 $vcdCmd = "sim step ${vcdStart}; ${vcdCmd}";
rlm@67 233 }
rlm@67 234
rlm@67 235 if (defined($bluesimCmd)) {
rlm@67 236 $bluesimCmd .= " ";
rlm@67 237 }
rlm@67 238 else {
rlm@67 239 $bluesimCmd = "";
rlm@67 240 }
rlm@67 241 $bluesimCmd .= "-c \"$vcdCmd\"";
rlm@67 242 }
rlm@67 243
rlm@67 244 if (defined($bluesimCmd)) {
rlm@67 245 $cmd .= " --bluesim=\'$bluesimCmd\'";
rlm@67 246 }
rlm@67 247
rlm@67 248 # Adjust the arguments for Bluesim if it is being invoked directly
rlm@67 249 if (! $config{isHybridModel} && ($mType == $MODEL_BLUESIM)) {
rlm@67 250 $cmd =~ s/\s--/ +--/g;
rlm@67 251
rlm@67 252 # Bluesim may expect to load a program from a well known file
rlm@67 253 unlink('program.vmh');
rlm@67 254 link("program/$config{workload}.$config{ISA}.vmh", 'program.vmh');
rlm@67 255 }
rlm@67 256
rlm@67 257
rlm@67 258 #############################################################################
rlm@67 259 #############################################################################
rlm@67 260 ##
rlm@67 261 ## Load the FPGA and run the model
rlm@67 262 ##
rlm@67 263 #############################################################################
rlm@67 264 #############################################################################
rlm@67 265
rlm@67 266 #
rlm@67 267 # Move old stats file so we are sure statistics come from this run
rlm@67 268 #
rlm@67 269 if (-f "$config{workload}.stats") {
rlm@67 270 rename("$config{workload}.stats", "$config{workload}.stats.old");
rlm@67 271 }
rlm@67 272
rlm@67 273 if ($mType == $MODEL_FPGA) {
rlm@67 274 if (! defined($printCycle)) {
rlm@67 275 # User didn't specify a cycle printing interval. Pick one more reasonable
rlm@67 276 # for HW.
rlm@67 277 #$cmd .= " --pc=10000000";
rlm@67 278 }
rlm@67 279
rlm@67 280 # Load FPGA
rlm@67 281 $ENV{FPGA_BIT_FILE} = "$config{modelDir}/.xilinx/$config{model}_par.bit";
rlm@67 282
rlm@67 283 if (! $noProgram) {
rlm@67 284 if (! $forceLoad && -s "$config{modelDir}/$config{model}_hw.errinfo") {
rlm@67 285 print STDERR "FPGA bit file has errors:\n\n";
rlm@67 286 system("cat $config{modelDir}/$config{model}_hw.errinfo > /dev/stderr");
rlm@67 287 print STDERR "\nUse --force-load to ignore the error.\n";
rlm@67 288 exit(1);
rlm@67 289 }
rlm@67 290
rlm@67 291 if (! $noReserve) {
rlm@67 292 Exec("hasim-fpga-ctrl --reserve", "Failed to reserve FPGA");
rlm@67 293 }
rlm@67 294
rlm@67 295 # Does a download script exist to program the FPGA?
rlm@67 296 my $needProgram = (-f "$config{modelDir}/config/$config{model}.download");
rlm@67 297 $needProgram = 1;
rlm@67 298
rlm@67 299 # Is the FPGA already programmed with the correct bit file?
rlm@67 300 if (exists($config{signature})) {
rlm@67 301 my $curSignature = `hasim-fpga-ctrl --getsignature`;
rlm@67 302 chomp($curSignature);
rlm@67 303 if ($curSignature eq $config{signature}) {
rlm@67 304 print "FPGA is already programmed (signature match)...\n";
rlm@67 305 #$needProgram = 0;
rlm@67 306 }
rlm@67 307 }
rlm@67 308
rlm@67 309 if ($needProgram) {
rlm@67 310 Exec("hasim-fpga-ctrl --program", "Failed to enter FPGA programming mode");
rlm@67 311
rlm@67 312 my $dir = `pwd`;
rlm@67 313 chomp($dir);
rlm@67 314 Exec("(cd $config{modelDir}; ./config/$config{model}.download ${dir}/FPGA_programming.log)", "Failed to program FPGA");
rlm@67 315
rlm@67 316 if (exists($config{signature})) {
rlm@67 317 Exec("hasim-fpga-ctrl --setsignature=$config{signature}", "Failed to set FPGA bit image signature");
rlm@67 318 }
rlm@67 319 }
rlm@67 320
rlm@67 321 Exec("hasim-fpga-ctrl --activate", "Failed to activate FPGA or driver");
rlm@67 322 }
rlm@67 323 }
rlm@67 324
rlm@67 325 # Run the software side or a hardware simulator
rlm@67 326 my $run_status = 0;
rlm@67 327 if ($config{isHybridModel} || ($mType != $MODEL_FPGA)) {
rlm@67 328 $cmd = $cmd." 2> proc.trace\n";
rlm@67 329 $run_status = ExecModel($cmd);
rlm@67 330 }
rlm@67 331
rlm@67 332 # Create a stats file for null workloads to make regression.launcher happy (HACK)
rlm@67 333 if ( $config{workload} eq "null" ) {
rlm@67 334 system("touch null.stats");
rlm@67 335 }
rlm@67 336
rlm@67 337 if (-f "hasim_events.out") {
rlm@67 338 system("sort hasim_events.out -o hasim_events.out.$$; mv -f hasim_events.out.$$ hasim_events.out");
rlm@67 339 }
rlm@67 340 if (-f "$config{workload}.stats") {
rlm@67 341 system("sort $config{workload}.stats -o $config{workload}.stats.$$; mv -f $config{workload}.stats.$$ $config{workload}.stats");
rlm@67 342 }
rlm@67 343
rlm@67 344 if (($mType == $MODEL_FPGA) && ! $noProgram && ! $noReserve) {
rlm@67 345 Exec("hasim-fpga-ctrl --drop-reservation", "Failed to drop FPGA reservation");
rlm@67 346 }
rlm@67 347
rlm@67 348 if ($run_status != 0) {
rlm@67 349 exit($run_status);
rlm@67 350 }
rlm@67 351 else {
rlm@67 352 exit(CompareOutput());
rlm@67 353 }
rlm@67 354
rlm@67 355
rlm@67 356 sub ErrorExit($) {
rlm@67 357 my $msg = shift;
rlm@67 358
rlm@67 359 print STDERR "${msg}\n";
rlm@67 360
rlm@67 361 if (($mType == $MODEL_FPGA) && ! $noProgram && ! $noReserve) {
rlm@67 362 system("hasim-fpga-ctrl --drop-reservation");
rlm@67 363 }
rlm@67 364
rlm@67 365 exit(1);
rlm@67 366 }
rlm@67 367
rlm@67 368
rlm@67 369 ##
rlm@67 370 ## ExecModel --
rlm@67 371 ## This is the routine that actually invokes the model. stdout and stderr
rlm@67 372 ## are logged in a file. The return value is the exit status of the model.
rlm@67 373 ##
rlm@67 374 sub ExecModel($) {
rlm@67 375 my $cmd = shift;
rlm@67 376
rlm@67 377 if ($gdb) {
rlm@67 378 ## gdb needs stdin. Just use system() and don't do logging.
rlm@67 379 system("gdb -args " . $cmd);
rlm@67 380 return 0;
rlm@67 381 }
rlm@67 382
rlm@67 383 ##
rlm@67 384 ## Invoke the model, but log its output both to stdout and to a file.
rlm@67 385 ## Use a pty so the invoked program will use line buffering instead
rlm@67 386 ## of fully buffered writes. (Libc sets up stdout line buffered when
rlm@67 387 ## it thinks it is writing to a terminal. It uses fully buffered
rlm@67 388 ## writing to a pipe.)
rlm@67 389 ##
rlm@67 390
rlm@67 391 my $pty = new IO::Pty;
rlm@67 392 my $slave = $pty->slave();
rlm@67 393
rlm@67 394 my $pid = fork();
rlm@67 395 die "Couldn't fork: $!" unless defined $pid;
rlm@67 396
rlm@67 397 if (! $pid) {
rlm@67 398 # Child process is the monitoring process
rlm@67 399 $pty->make_slave_controlling_terminal();
rlm@67 400
rlm@67 401 my $output = "$config{workload}.$config{ISA}.out";
rlm@67 402 if(exists($config{silent})) {
rlm@67 403 $output = "/dev/null";
rlm@67 404 }
rlm@67 405
rlm@67 406 if (! open(LOG, ">$output")) {
rlm@67 407 print STDERR "Error opening log file $output\n";
rlm@67 408 }
rlm@67 409
rlm@67 410 # Unbuffered I/O loop
rlm@67 411 while (1) {
rlm@67 412 my $buf;
rlm@67 413 my $n = sysread($slave, $buf, 4096);
rlm@67 414
rlm@67 415 last if ($n == 0);
rlm@67 416
rlm@67 417 syswrite(STDOUT, $buf);
rlm@67 418 syswrite(LOG, $buf);
rlm@67 419 }
rlm@67 420
rlm@67 421 close(LOG);
rlm@67 422 exit(0);
rlm@67 423 }
rlm@67 424
rlm@67 425 # Bind new PTY to STDOUT (but save old STDOUT)
rlm@67 426 $pty->close_slave();
rlm@67 427 open(my $oldOut, ">&", STDOUT) or die $!;
rlm@67 428 open(STDOUT, ">&", $pty) or die $!;
rlm@67 429
rlm@67 430 # Run model
rlm@67 431 my $result = system("${cmd} 2>&1");
rlm@67 432
rlm@67 433 # Send ^d to end child logging thread
rlm@67 434 print "\cD";
rlm@67 435
rlm@67 436 # Return to normal STDOUT
rlm@67 437 close(STDOUT);
rlm@67 438 open(STDOUT, ">&", $oldOut) or die $!;
rlm@67 439 close($oldOut);
rlm@67 440
rlm@67 441 # Compute exit status of model
rlm@67 442 my $status = 0;
rlm@67 443 if ($result == -1) {
rlm@67 444 print STDERR "Model execution failed\n";
rlm@67 445 $status = 1;
rlm@67 446 }
rlm@67 447 elsif ($result & 127) {
rlm@67 448 print STDERR "Child died with signal " . ($result & 127) . ", " . (($result & 128) ? 'with' : 'without') . " coredump\n";
rlm@67 449 $status = 1;
rlm@67 450 }
rlm@67 451 elsif (($result >> 8) != 0) {
rlm@67 452 $status = $result >> 8;
rlm@67 453 print "Model exited with status $status\n";
rlm@67 454 }
rlm@67 455
rlm@67 456 return $status;
rlm@67 457 }
rlm@67 458
rlm@67 459
rlm@67 460 sub Exec($$) {
rlm@67 461 my $cmd = shift;
rlm@67 462 my $errmsg = shift;
rlm@67 463
rlm@67 464 system($cmd);
rlm@67 465 if ($? == -1) {
rlm@67 466 ErrorExit("Failed to execute $cmd: $!");
rlm@67 467 }
rlm@67 468 elsif ($? & 127) {
rlm@67 469 ErrorExit("Child died with signal " . ($? & 127) . ", " . (($? & 128) ? 'with' : 'without') . " coredump");
rlm@67 470 }
rlm@67 471 elsif (($? >> 8) != 0) {
rlm@67 472 ErrorExit("${errmsg}");
rlm@67 473 }
rlm@67 474 }
rlm@67 475
rlm@67 476
rlm@67 477 sub CompareOutput() {
rlm@67 478 return 0 if ($noCompare != 0);
rlm@67 479 return 0 if (! exists($config{compare}) || ($config{compare} eq ''));
rlm@67 480
rlm@67 481 # run the checker
rlm@67 482 `cd ./checker/ && make clean && make`;
rlm@67 483 `./checker/checker input.wav out_gold.wav`;
rlm@67 484 print "about to call compare_wavs\n";
rlm@67 485 my $out=`./checker/compare_wavs/compare_wavs 10 out_gold.wav out_hw.wav`;
rlm@67 486
rlm@67 487 if ($out !~ /fail/) {
rlm@67 488 print "*** Output comparison passed ***\n";
rlm@67 489 system("touch $config{workload}.stats");
rlm@67 490 return 0;
rlm@67 491 }
rlm@67 492 else {
rlm@67 493 print "*** Output comparison failed ***\n";
rlm@67 494 return 1;
rlm@67 495 }
rlm@67 496 }
rlm@67 497
rlm@67 498
rlm@67 499 #
rlm@67 500 # Read the configuration file
rlm@67 501 #
rlm@67 502 sub ReadConfig($$) {
rlm@67 503 my $conf = shift;
rlm@67 504 my $required = shift;
rlm@67 505
rlm@67 506 my $status = open(CONFIG, "< $conf");
rlm@67 507 if (! $status) {
rlm@67 508 return if (! $required);
rlm@67 509 die("Failed to open $conf");
rlm@67 510 }
rlm@67 511
rlm@67 512 while (<CONFIG>) {
rlm@67 513 chomp;
rlm@67 514 my $t = $_;
rlm@67 515 $t =~ s/#.*//;
rlm@67 516 if ($t =~ /^\s*([^\s]+)\s*=\s*"(.*)"\s*$/) {
rlm@67 517 my $c = $1;
rlm@67 518 my $v = $2;
rlm@67 519 $v =~ s/^["'](.*)["']$/$1/; # Drop quotation marks
rlm@67 520 $config{$c} = $v;
rlm@67 521 }
rlm@67 522 elsif ($t =~ /^\s*([^\s]+)\s*=\s*([^\s]+)\s*$/) {
rlm@67 523 my $c = $1;
rlm@67 524 my $v = $2;
rlm@67 525 $config{$c} = $v;
rlm@67 526 }
rlm@67 527 }
rlm@67 528 }