#!/usr/local/bin/perl
#
# @(#) memconf - Identify sizes of SIMM/DIMM memory modules installed
# @(#) Micron Technology, Inc. - Tom Schmidt 17-Sep-98 V1.5.1
#
# Maintained by Tom Schmidt (tschmidt@micron.com)
#
#   If memconf does not recognize a system, then please send the output of
#   '/usr/sbin/prtconf -pv' (or '/usr/etc/devinfo -pv' on Solaris 1.X) to
#   tschmidt@micron.com so that memconf can be enhanced to recognize it.
#
# Based on SunManagers SUMMARY by howie@warlok.ds.boeing.com (Howard Modell)
# on 29-Jan-97.
#
# Tested to work on:
# - sun4c SS2
# - sun4m 4/6x0, SS5, SS10, SS10SX, SS20, LX/ZX
# - sun4d SPARCserver-1000
# - sun4u Ultra 1, 2, 5, 30, 450
# - sun4u Enterprise 3000, 4000/5000
#
# Untested systems that should work:
# - sun4m SS4, Classic/ClassicX (with verbose output)
# - sun4m Xterminal-1, Voyager (no verbose output)
# - sun4d SPARCcenter-2000 (with verbose output)
# - sun4u Ultra 10 (with verbose output)
# - sun4u Ultra 60 (with verbose output, guessing on bank address range)
# - sun4u Enterprise 6000 (with verbose output)
# - sun4u1 Enterprise 10000 (no verbose output)
#
# Won't work on:
# - Systems without /dev/openprom
# - sun4c SS1, SS1+, IPC, IPX, SLC, ELC (no 'memory' lines in devinfo/prtconf
#   output)
# - sun4 kernel architecture, and sun3 and older systems
#
# To Do:
# - Report empty slots as well in verbose mode.
# - Recognize VME bus memory cards in 4/6x0.
# - Recognize 4MB and 8MB VSIMMs on SS10SX and SS20SX (not in total memory).
#   May be confused by Solaris 2.X sxconfig(1M) command.
# - Distinguish between SIMMs and DIMMs.
# - Test on untested systems above, adding verbose to those that lack it.
# - Add newer systems as they come out.
#
# Revision History:
# - 29-Jan-97 - V1.0 - From SunManagers SUMMARY by howie@warlok.ds.boeing.com
#	(Howard Modell)
# - 05-Feb-97 - V1.1 - Ported to SunOS, added slot information, etc.
# - 17-Aug-98 - V1.2 - Added Ultra-30, Ultra Enterprise 4000/5000.
# - 18-Aug-98 - V1.2.1 - Added Ultra-5.
# - 20-Aug-98 - V1.3 - Fixed SS10SX. Added Ultra Enterprise 3000.
# - 02-Sep-98 - V1.3.1 - Cleanup Ultra 450 recognition.
# - 15-Sep-98 - V1.4 - Added verbose output for Sun 4/30 LX/ZX and Classic.
# - 17-Sep-98 - V1.5 - Added verbose output for SPARCserver 1000 and SPARCcenter
#			2000. Added untested Ultra-60 verbose output.
# - 17-Sep-98 - V1.5.1 - Fixed Ultra 450.

$BSD = -f '/vmunix';
if ($BSD) {
	if (! -f '/usr/etc/devinfo') {
		printf "ERROR: no 'devinfo' command. Aborting.\n";
		exit;
	}
	$config_cmd = "/usr/etc/devinfo -pv";
} else {
	if (! -f '/usr/sbin/prtconf') {
		printf "ERROR: no 'prtconf' command. Aborting.\n";
		exit;
	}
	$config_cmd = "/usr/sbin/prtconf -pv";
}
@config = `$config_cmd`;
$hostname = `/usr/bin/uname -n`;
chop $hostname;
$filename = "";
$memory_size = "";
$installed_memory = 0;
$ultra = 0;
$simmbanks = 0;
$simmspergroup = 1;
$prtconfgroups = 1;
$bankcnt = 0;
$slot0 = 0;
$largestsimm = 0;
$found32mb = 0;
$sx = 0;
$memtype = "SIMM";
$verbose = 0;
#
# Parse options
#
if (-f "$ARGV[0]") {
	# Test file with prtconf/devinfo output
	@config = `/bin/cat $ARGV[0]`;
	$hostname = "";
	$filename = "$ARGV[0]";
	$verbose = 2;
} elsif ($ARGV[0] eq "-v") {
	$verbose = 1;
} elsif ($ARGV[0] eq "-d") {
	$verbose = 2;
} elsif ($#ARGV > -1) {
	printf "Usage: memconf [-v]\n";
	exit;
}

sub header {
	if ("$hostname" ne "") {
		printf("hostname: $hostname\n");
	}
	if ("$filename" ne "") {
		printf("filename: $filename\n");
	}
	if ($verbose eq 0) {
		if ("$banner" ne "") {
			printf("$banner\n");
		} elsif ("$model" ne "") {
			printf("$model\n");
		}
	} else {
		if ("$banner" ne "") {
			printf("banner:   $banner\n");
		}
		if ("$model" ne "") {
			printf("model:    $model\n");
		}
	}
	if ($verbose > 1) {
#		printf "ultra = $ultra\n" if ($ultra != 0 | $ultra eq "e");
		printf "memory line: $gotmemory\n" if ("$gotmemory" ne "");
#		printf "module info: $gotmodule\n" if ("$gotmodule" ne "");
	}
}

$i = 0;
$banner = "";
$model = "";
foreach $line (@config) {
	if ($line =~ /banner-name:/) {
		$banner = $line;
		$banner =~ s/\s+banner-name:\s+//;
		$banner =~ s/'//g;
		chop $banner;
		if ($line =~ /Enterprise/) { $ultra = "e"; }
		if ($line =~ /Ultra 1/) { $ultra = 1; }
		if ($line =~ /Ultra 2/) { $ultra = 2; }
		if ($line =~ /Ultra 5/) { $ultra = 5; }
		if ($line =~ /Ultra 10/) { $ultra = 10; }
		if ($line =~ /Ultra 30/) { $ultra = 30; }
		if ($line =~ /Ultra 60/) { $ultra = 60; }
		if ($line =~ /450/) { $ultra = 450; }
	}
	if ($line =~ /SUNW,Ultra-/ | $line =~ /SUNW,SPARC/ | $line =~ /Sun 4/) {
		$model = $line;
		$model =~ s/\s+name:\s+//;
		$model =~ s/'//g;
		$model =~ s/SUNW,//g;
		chop $model;
		if ($model =~ /Ultra-1/) { $ultra = 1; }
		if ($model =~ /Ultra-2/) { $ultra = 2; }
		if ($model =~ /Ultra-5/) { $ultra = 5; }
		if ($model =~ /Ultra-5_10/) { $ultra = 5; }
		if ($model =~ /Ultra-30/) { $ultra = 30; }
		if ($model =~ /Ultra-60/) { $ultra = 60; }
		if ($model =~ /Ultra-4/) { $ultra = 450; }
		if ($model =~ /Ultra-Enterprise/) { $ultra = "e"; }
	}
	if ($line =~ /\sname:\s+'memory'/) {
		$j = $i - 2;
		if ($config[$j] =~ /\sreg:/) {
			$gotmemory = $config[$j];
			chop $gotmemory;
#			goto GotMemory;
		}
	}
	if ($line =~ /\sdevice_type:\s+'memory-bank'/) {
		$j = $i - 3;
		if ($config[$j] =~ /\sreg:/ & $config[$j] !~ /.00000000$/) {
			$config[$j] =~ s/\s+reg:\s+//;
			if ("$gotmemory" ne "") {
				$gotmemory = $gotmemory . "." . $config[$j];
			} else {
				$gotmemory = $config[$j];
			}
			chop $gotmemory;
		}
	}
	# The following is not used yet
	#if ($line =~ /\sdevice_type:\s+'memory-module'/) {
	#	if ($config[$i - 2] =~ /\sreg:/) {
	#		$config[$i - 3] =~ s/\s+socket-name:\s+//;
	#		if ("$gotmodule" ne "") {
	#			$gotmodule = $gotmodule . "." . $config[$i - 3];
	#		} else {
	#			$gotmodule = $config[$i - 3];
	#		}
	#		chop $gotmodule;
	#		$config[$i - 2] =~ s/\s+reg:\s+//;
	#		@module = split(/\./, $config[$i - 2]);
	#		$gotmodule = $gotmodule . "." . $module[3];
	#		chop $gotmodule;
	#		$config[$i + 1] =~ s/\s+name:\s+//;
	#		$config[$i + 1] =~ y/[a-z]/[A-Z]/;
	#		$gotmodule = $gotmodule . "." . $config[$i + 1];
	#		chop $gotmodule;
	#		$gotmodule =~ s/'//g;
	#	}
	#}
	if ($line =~ /\sname:\s+'cgfourteen'/) {
		$sx = 1;
	}
	if ($line =~ /Memory size:\s/) {
		$memory_size = $line;
		chop $memory_size;
		@memory = split(/\s/, $memory_size);
		$installed_memory = $memory[2];
		$BSD = 0;	# prtconf only has this output
		$config_cmd = "/usr/sbin/prtconf -pv";
	}
	$i = $i + 1;
}
if ("$gotmemory" eq "") {
	header;
	if ($installed_memory > 0) {
		printf "total memory = " . $installed_memory . "MB\n";
	}
	printf "ERROR: no 'memory' line in \"$config_cmd\" output.\n";
	if (! $BSD) {
		printf "       This is most likely because memconf does not ";
		printf "recognize this system.\n";
		printf "       Send the output of \"$config_cmd\" ";
		printf "to tschmidt\@micron.com\n";
		printf "       so that memconf can be enhanced to recognize ";
		printf "this system.\n";
	}
	exit;
}

GotMemory:
$gotmemory =~ s/\s+reg:\s+//;
$gotmemory =~ s/'//g;
@slots = split(/\./, $gotmemory);
$slot = 1;
$totmem = 0;
header;
$machine = `/usr/bin/uname -m`;
# DIMMs are installed in pairs on Ultra 1, 5, and 10; quads on
# Ultra 2, 60, 450; 8's in Enterprise
if ($machine =~ /sun4u/ | $ultra != 0 | $ultra eq "e") {
	$val0 = 3;	# simmsize is in 4th field
	$valaddr = 2;	# address is 2 fields before simmsize
	$valinc = 4;	# fields per simm
	$memtype = "DIMM";
} else {
	$val0 = 2;	# simmsize is in 3rd field
	$valaddr = 1;	# address is 1 field before simmsize
	$valinc = 3;	# fields per simm	# fields per simm
}
if ($ultra eq "e" | $ultra == 60) {
	$valinc = 8;	# fields per prtconf group
}

#
# define SIMM layout for specific systems
#
if ("$model" eq "Sun 4/75") {
	# Accepts 4MB SIMMs on motherboard and 32MB or 64MB SBus expansion card
	$simmrangex = "01000000";
	$simmbanks = 4;
	$simmsperbank = 4;
	@socketstr = qw(U0311 U0309 U0307 U0322 U0312 U0310 U0308 U0321 U0313 U0314 U0315 U0320 U0319 U0318 U0317 U0316);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3);
	@bytestr = qw(0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3);
}
if ("$model" =~ /SPARCstation-LX/ | "$model" =~ /SPARCclassic/) {
	# LX (4/30) and Classic (4/15) accept 4MB and 16MB SIMMs on motherboard
	# Classic-X (4/10) accepts 1MB, 2MB and 4MB SIMMs on motherboard
	$simmrangex = "02000000";
	$simmbanks = 3;
	$simmsperbank = 2;
	@socketstr = qw(U0304 U0303 U0301 U0302 U0402 U0401);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(1 1 2 2 3 3);
	@bytestr = qw();
}
if ("$model" eq "SPARCstation-4") {
	# Accepts 8MB and 32MB SIMMs on motherboard
	$simmrangex = "02000000";
	$simmbanks = 5;
	$simmsperbank = 1;
	@socketstr = qw(J0301 J0302 J0303 J0304 J0305);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0 1 2 3 4);
	@bytestr = qw();
}
if ("$model" eq "SPARCstation-5") {
	# Accepts 8MB and 32MB SIMMs on motherboard
	$simmrangex = "02000000";
	$simmbanks = 8;
	$simmsperbank = 1;
	@socketstr = qw(J0300 J0301 J0302 J0303 J0400 J0401 J0402 J0403);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0 1 2 3 4 5 6 7);
	@bytestr = qw();
}
if ("$model" =~ /SPARCstation-10/) {
	# Accepts 16MB and 64MB SIMMs on motherboard
	$simmrangex = "04000000";
	$simmbanks = 8;
	$simmsperbank = 1;
	@socketstr = qw(J0201 J0203 J0302 J0304 J0202 J0301 J0303 J0305);
	@orderstr = qw(1st 3rd 4th 2nd 8th 6th 5th 7th);
	@groupstr = qw();
	@bankstr = qw(0 1 2 3 4 5 6 7);
	@bytestr = qw();
}
if ("$model" eq "SPARCstation-20") {
	# Accepts 16MB, 32MB and 64MB SIMMs on motherboard
	$simmrangex = "04000000";
	$simmbanks = 8;
	$simmsperbank = 1;
	@socketstr = qw(J0201 J0303 J0202 J0301 J0305 J0203 J0302 J0304);
	@orderstr = qw(1st 2nd 3rd 4th 5th 6th 7th 8th);
	@groupstr = qw();
	@bankstr = qw(0 1 2 3 4 5 6 7);
	@bytestr = qw();
}
if ("$model" eq "SPARCsystem-600") {
	# Accepts 4MB or 16MB SIMMs on motherboard, 1MB or 4MB SIMMs on VME
	# expansion card
	$simmrangex = "10000000";
	$simmbanks = 2;
	$simmsperbank = 16;
	@socketstr = qw(U1107 U1307 U1105 U1305 U1103 U1303 U1101 U1301 U1207 U1407 U1205 U1405 U1203 U1403 U1201 U1401 U1108 U1308 U1106 U1306 U1104 U1304 U1102 U1302 U1208 U1408 U1206 U1406 U1204 U1404 U1202 U1402);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1);
	@bytestr = qw(0L0 0L1 1L0 1L1 2L0 2L1 3L0 3L1 4L0 4L1 5L0 5L1 6L0 6L1 7L0 7L1 0H0 0H1 1H0 1H1 2H0 2H1 3H0 3H1 4H0 4H1 5H0 5H1 6H0 6H1 7H0 7H1);
}
if ("$model" eq "SPARCserver-1000") {
	# Accepts 8MB and 32MB SIMMs on motherboard
	$simmrangex = "08000000";
	$simmbanks = 4;
	$simmsperbank = 4;
	@socketstr = qw(J2800 J2900 J3000 J3100 J3200 J3300 J3400 J3500 J3600 J3700 J3800 J3900 J4000 J4100 J4200 J4300);
	@orderstr = qw();
	@groupstr = qw(0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3);
	@bankstr = qw();
	@bytestr = qw();
}
if ("$model" eq "SPARCcenter-2000") {
	# Accepts 8MB and 32MB SIMMs on motherboard
	$simmrangex = "08000000";
	$simmbanks = 2;
	$simmsperbank = 8;
	@socketstr = qw(U4800 U5000 U4900 U5100 U4000 U4200 U4100 U4300 U4400 U4600 U4500 U4700 U3600 U3800 U3700 U3900);
	@orderstr = qw();
	@groupstr = qw(0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1);
	@bankstr = qw();
	@bytestr = qw();
}
if ("$model" eq "Ultra-1") {
	# Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard
	$memtype = "DIMM";
	$simmrangex = "10000000";
	$simmbanks = 4;
	$simmsperbank = 2;
	@socketstr = qw(U0701 U0601 U0702 U0602 U0703 U0603 U0704 U0604);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0L 0H 1L 1H 2L 2H 3L 3H);
	@bytestr = qw(00-15 16-31 00-15 16-31 00-15 16-31 00-15 16-31);
}
if ("$model" eq "Ultra-2") {
	# Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard
	$memtype = "DIMM";
	$simmrangex = "20000000";
	$simmbanks = 4;
	$simmsperbank = 4;
	@socketstr = qw(U0501 U0401 U0701 U0601 U0502 U0402 U0702 U0602 U0503 U0403 U0703 U0603 U0504 U0404 U0704 U0604);
	@orderstr = qw();
	@groupstr = qw(0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3);
	@bankstr = qw(0L 0H 1L 1H 0L 0H 1L 1H 0L 0H 1L 1H 0L 0H 1L 1H);
	@bytestr = qw(00-15 16-31 32-47 48-63 00-15 16-31 32-47 48-63 00-15 16-31 32-47 48-63 00-15 16-31 32-47 48-63);
}
if ("$model" eq "Ultra-30") {
	# Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard
	$memtype = "DIMM";
	$simmrangex = "20000000";
	$simmbanks = 4;
	$simmsperbank = 4;
	@socketstr = qw(U0701 U0801 U0901 U1001 U0702 U0802 U0902 U1002 U0703 U0803 U0903 U1003 U0704 U0804 U0904 U1004);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0L 0L 0H 0H 1L 1L 1H 1H 2L 2L 2H 2H 3L 3L 3H 3H);
	@bytestr = qw();
}
if ("$model" eq "Ultra-5_10") {
	# Accepts 16MB, 32MB, 64MB, 128MB, or 256MB DIMMs on motherboard
	$memtype = "DIMM";
	$simmrangex = "10000000";
	$simmbanks = 2;
	$simmsperbank = 2;
	@socketstr = qw(DIMM1 DIMM2 DIMM3 DIMM4);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0L 0H 1L 1H);
	@bytestr = qw();
}
if ("$model" eq "Ultra-60") {
	# Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard
	$memtype = "DIMM";
	$simmrangex = "40000000";
	$simmbanks = 4;
	$simmsperbank = 4;
	$prtconfgroups = 2;
	$valinc = 8;	# fields per prtconf group
	# I am guessing here on the order of the DIMM address range
	# Assume that bank 3 (top) is stuffed first (factory default)
	@socketstr = qw(U0801 U0802 U0803 U0804 U0701 U0702 U0703 U0704 U1001 U1002 U1003 U1004 U0901 U0902 U0903 U0904);
	@groupstr = qw();
	@bankstr = qw(1 1 1 1 0 0 0 0 3 3 3 3 2 2 2 2);
	@bytestr = qw();
}
if ("$model" eq "Ultra-4") {
	# Accepts 16MB, 32MB, 64MB, 128MB or 256MB DIMMs on motherboard
	$memtype = "DIMM";
	$simmrangex = "40000000";
	$simmbanks = 4;
	$simmsperbank = 4;
	@socketstr = qw(U1901 U1902 U1903 U1904 U1801 U1802 U1803 U1804 U1701 U1702 U1703 U1704 U1601 U1602 U1603 U1604);
	@orderstr = qw();
	@groupstr = qw(A A A A B B B B C C C C D D D D);
	@bankstr = qw(2 2 2 2 3 3 3 3 0 0 0 0 1 1 1 1);
	@bytestr = qw();
}
if ("$model" eq "Ultra-Enterprise") {
	# Accepts 8MB, 32MB or 128MB DIMMs on motherboard, 2 banks of 8 DIMMs
	$memtype = "DIMM";
	$simmrangex = "80000000";
	$simmbanks = 2;
	$simmsperbank = 8;
	$simmspergroup = 8;
	$prtconfgroups = 2;
	$valinc = 8;	# fields per prtconf group
	# Enterprise 3000, 4000, 5000, 6000
	@socketstr = qw(J3100-J3800 J3101-J3801);
	@orderstr = qw();
	@groupstr = qw();
	@bankstr = qw(0 1);
	@bytestr = qw();
}

for($val=$val0; $val < scalar(@slots); $val = $val + $valinc) {
	$simmsz = $slots[$val];
	$simmaddr = $slots[$val - $valaddr];
	if ($simmsz eq "80000000") { $simmsize = 2048; }
	if ($simmsz eq "40000000") { $simmsize = 1024; }
	if ($simmsz eq "20000000") { $simmsize = 512; }
	if ($simmsz eq "10000000") { $simmsize = 256; }
	if ($simmsz eq "08000000") { $simmsize = 128; }
	if ($simmsz eq "04000000") { $simmsize = 64; }
	if ($simmsz eq "02000000") { $simmsize = 32; }
	if ($simmsz eq "01000000") { $simmsize = 16; }
	if ($simmsz eq "00800000") { $simmsize = 8; }
	if ($simmsz eq "00400000") { $simmsize = 4; }
	if ($simmsz eq "00100000") { $simmsize = 1; }
	$simmsize = $simmsize * $prtconfgroups;
	$totmem += $simmsize;

	if ("$model" eq "Sun 4/75" & $simmbanks < $bankcnt + 2) {
		# SS2 SBus memory card
		if ("$simmaddr" eq "08000000") {
			printf "SBus primary contains ";
		} else {
			printf "SBus secondary contains ";
		}
		$simmstart = hex($simmaddr);
		$simmrange = hex($simmrangex);
		$simmstop = sprintf "%08lx", $simmstart + (2 * $simmrange) - 1;
		$totmem += $simmsize;
		$simmsize = $simmsize * 2;
		$val = $val + $valinc;
		printf $simmsize . "MB";
		if ($verbose) {
			printf " (address 0x$simmaddr - 0x$simmstop)";
		}
		printf "\n";
	} elsif ($simmbanks > 0) {
		$simmstart = hex($simmaddr);
		$simmrange = hex($simmrangex);
		$simmstop = sprintf "%08lx", $simmstart + $simmrange - 1;
		$cnt = 0;
		if ($simmspergroup > 1) {
			$maxcnt = $simmbanks * $simmsperbank / $simmspergroup / $prtconfgroups;
		} else {
			$maxcnt = $simmbanks * $simmsperbank;
		}
		while ($cnt < $maxcnt) {
			if ($simmstart == ($simmrange * $cnt)) {
				$bankcnt = $cnt;
				$cnt3 = ($bankcnt * $simmsperbank);
				$socket = $socketstr[$cnt3];
				$order = $orderstr[$cnt3];
				$group = $groupstr[$cnt3];
				$bank = $bankstr[$cnt3];
				$byte = $bytestr[$cnt3];
			}
			$cnt = $cnt + 1;
		}
		#
		# Check for 32MB SIMM. A 32MB SIMM is sometimes seen as 2 16MB
		# SIMMs.  This may report more slots than are really in a system
		# (i.e. a SS20 with 8 32MB SIMMs reports 16 slots of 16MB each).
		#
		$start = $simmstart + ($simmrange / 2);
		$startx = sprintf "%08lx", $start;
		if ($slots[$val - 1 + $valinc] eq $startx) {
			$found32mb = 1;
			$totmem += $simmsize;
			$simmsize = $simmsize * 2;
			$val = $val + $valinc;
		}
#		if ($ultra eq "e") {
#			$val = $val + $valinc;
#		}
		if ($simmstart == 0) {
			$slot0 = $simmsize;
		}
		if ($simmsize > $largestsimm) {
			$largestsimm = $simmsize;
		}

		$cnt2 = 0;
		if ($simmspergroup > 1) {
			$maxcnt2 = $simmsperbank / $simmspergroup;
		} else {
			$maxcnt2 = $simmsperbank;
		}
		while ($cnt2 < $maxcnt2) {
			if ($simmspergroup > 1) {
				printf "sockets $socket have $simmsperbank ";
				printf $simmsize/$simmsperbank . "MB ${memtype}s";
			} else {
				printf "socket $socket has a ";
				printf $simmsize/$simmsperbank . "MB $memtype";
			}
			if ($verbose) {
				printf " (";
				if ("$order" ne "") {
					printf "$order $memtype, ";
				}
				if ("$group" ne "") {
					printf "group $group, ";
				}
				if ("$bank" ne "") {
					printf "bank $bank, ";
				}
				if ("$byte" ne "") {
					printf "byte $byte, ";
				}
				printf "address 0x$simmaddr - 0x$simmstop)";
			}
			printf "\n";
			$cnt2 = $cnt2 + 1;
			$cnt3 = ($bankcnt * $simmsperbank) + $cnt2;
			$socket = $socketstr[$cnt3];
			$order = $orderstr[$cnt3];
			$group = $groupstr[$cnt3];
			$bank = $bankstr[$cnt3];
			$byte = $bytestr[$cnt3];
		}
	} elsif ($ultra == 1 | $ultra == 5 | $ultra == 10 | $ultra == 30) {
		printf "bank $slot has a pair of " . $simmsize/2 . "MB DIMMs\n";
	} elsif ($ultra == 2 | $ultra == 450) {
		printf "group $slot has four " . $simmsize/4 . "MB DIMMs\n";
	} elsif ($ultra == 60) {
		printf "group $slot has four " . $simmsize/2 . "MB DIMMs\n";
		$totmem += $simmsize;
	} elsif ($ultra eq "e") {
		printf "group $slot has eight " . $simmsize/4 . "MB DIMMs\n";
		$totmem += $simmsize;
	} else {
		printf "slot $slot has a " . $simmsize . "MB $memtype\n";
	}
	$slot = $slot + 1;
}
if ($sx) {
	if ("$model" eq "SPARCstation-20") {
		printf "socket J0304";
	} else {
		# SS10SX
		printf "socket J0301";
	}
	printf " has a VSIMM installed for SX graphics\n";
}
printf "total memory = " . $totmem . "MB\n";
 
#
# Check for illegal SIMM stuffings
#
if ("$model" =~ /SPARCstation-10/) {
	if ($slot0 < $largestsimm & $BSD) {
		printf "ERROR: Install the highest capacity SIMM in socket ";
		printf "$socketstr[0] under Solaris 1.X.\n";
	}
	if ($found32mb) {
		printf "ERROR: The 32MB SIMM is not supported in the SS10 ";
		printf "or SS10SX.\n";
	}
}

#
# Check for possible memory detection errors by this program
#
if ($installed_memory > 0) {
	if ($installed_memory != $totmem) {
		printf "ERROR: Total memory installed (${installed_memory}MB) ";
		printf "does not match total memory found (${totmem}MB\n";
		printf "       This is most likely because memconf does not ";
		printf "recognize this system.\n";
		printf "       Send the output of \"$config_cmd\" ";
		printf "to tschmidt\@micron.com\n";
		printf "       so that memconf can be enhanced to recognize ";
		printf "this system.\n";
	}
}

