Mac-1 Source Code

[ Main Page | Pseudocode | Source Code | Sample Output ]

Below is the current code for my assembler. Because of numerous complaints about size, readability, and formatting errors, this is now a previously imported version of the code rather than the "live version."

#!/usr/local/bin/perl

######################################################################
#
# This is ass.pl, an assembler for the Mac-1 instruction set.
# It was written by Chris Hardie and most recently revised on 12/07/97
#
# The program reads a program from a text file and outputs binary code
# in a text file, both defined by the user.
#
######################################################################


# Define user variables

$input_file = "/clients/users/silas/www/cs63/program/code/input.txt";
$output_file = "/clients/users/silas/www/cs63/program/code/output.txt";
$inst_size = 16;

# Main program

&create_set;
&input;

exit;

# Subroutines

sub create_set {
###############################
#
# This defines the Mac-1 instruction set and the binary equivalents
#
# I considered seperating the hash arrays by the number of bits contained
# in the binary equivalent of the instruction, but found that lookup is 
# easier when it's all in one.
#
###############################

	%all_commands = (
		"LODD" => "0000",
                "STOD" => "0001",
                "ADDD" => "0010",
                "SUBD" => "0011",
                "JPOS" => "0100",
                "JZER" => "0101",
                "JUMP" => "0110",
                "LOCO" => "0111",
                "LODL" => "1000",
                "STOL" => "1001",
                "ADDL" => "1010",
                "SUBL" => "1011",
                "JNEG" => "1100",
                "JNZE" => "1101",
                "CALL" => "1110",
		"INSP" => "11111100",
		"DESP" => "11111110",
		"PSHI" => "1111000000000000",
		"POPI" => "1111001000000000",
		"PUSH" => "1111010000000000",
		"POP"  => "1111011000000000",
		"RETN" => "1111100000000000",
		"SWAP" => "1111101000000000",
		"HALT" => "1111111111111111"
	);
	# "HALT" added by me to accommodate "CALL STOP"

	# For development only
	%labels_tst = (
		"PMUL" => "16",
		"ANOTZ" => "17",
		"BNOTZ" => "18",
		"L1" => "19",
		"L2" => "20",
		"DONE" => "21",
		"INNER" => "22",
		"L3" => "23",
		"MAIN" => "24",
		"L4" => "25",
		"C1" => "26",
		"C20" => "27"
	); 


}

sub input {
###############################
#
# This reads input from a file; it is the driver for the rest of the
# program, as the bulk of operations performed are on an single line from 
# the input file. This function calls &convert.
#
###############################

#########
# Pass I
#########

	open(INPUT,"$input_file") || die "Could not open input file.\n";

	$position = 0;

	while ($line = <INPUT>) {
		chop($line);
		@array = split(/ /, $line);

		$_ = $array[0];
		if (/:/) {
			$label = shift(@array);
			chop($label);
			$labels{$label} = $position;
		} 
		$_ = $line;
		if (!(/.*=.*/)) {
			$position = $position + $inst_size;
		}
	}

	close(INPUT);

#########
# Pass II
#########
	open(INPUT,"$input_file") || die "Could not open input file.\n";
	open(OUTPUT,">$output_file") || die "Could not open output file.\n";

	$line_number = 0;

	while ($line = <INPUT>) {

		undef($inst); undef($var); undef($array);
		chop($line);
		$line_number++;
		@array = split(/ /, $line);

#		print $line;
# For debugging

		$_ = $line;
		if (/.*=.*/) {
			($varname, $temp, $varvalue) = @array;
			$symbols{$varname} = $varvalue;
			next;
		}

		$_ = $array[0];
		if (/:/) {
			shift(@array);
		} 

		($inst) = @array[0];
	       	if (defined(@array[1])) {
		        ($var)  = @array[1];
		}

	print "Converting line $line_number:\n";
	&convert;

	}

	close(INPUT);
	close(OUTPUT);

}

sub convert {
###############################
#
# This converts the instructions to binary code.
#
# It is slightly tricky as it does some operations based on the hard coded
# instruction set and would not be able to handle an entirely new
# instruction set without some serious reworking.  Then again, this is true
# of the entire program. This function calls &int2bin
#
#
###############################

	@keys = keys %all_commands;
	$found = 0;
	foreach $key (@keys) {
		$_ = $key;
		if (/.*$inst.*/) {
			$found = 1;
		}
	}
	if ($found != 1) {
		die "Invalid instruction \"$inst\" at line number $line_number\n"; 
	}

	$valid = 0;
	$_ = $var;
	if (/[a-zA-Z]/) {

		@keys = keys %symbols;
		$found = 0;
		foreach $key (@keys) {
			$_ = $key;
			if (/.*$var.*/) {
				$found = 1;
			}
		}
		if ($found == 1) {
                        $valid = 1;
			$var = $symbols{$var};
		}	

	}
	
	$_ = $var;
	if ((/[a-zA-Z]/) && ($valid != 1)) {

		@keys = keys %labels;
		$found = 0;
		foreach $key (@keys) {
			$_ = $key;
			if (/.*$var.*/) {
				$found = 1;
			}
		}
		if ($found == 1) {
                        $valid = 1;
			$var = $labels{$var};
		}
	}

	$_ = $var;
	if (/[a-zA-Z]/) {
		if ($valid != 1) {
			die "Invalid parameter/label \"$var\" at line number
			$line_number\n"; 
		}		
	}

	$binary_inst = $all_commands{$inst};
        $inst_length = length($binary_inst);

	SWITCH: {

		if (($inst_length == 4) && (($var >= 4096) || ($var < 0) || ($var
				eq ""))) {
			die "Out of range paramater value \"$var\" at line number
				$line_number\n"; 
		}
	
		if (($inst_length == 8) && (($var >= 256) || ($var < 0) || ($var
				eq ""))) {
			die "Out of range paramater value \"$var\" at line number
				$line_number\n"; 
		}
		if (($inst_length == 16) && ($var ne "")) {
			die "Unexpected paramater \"$var\" at line number $line_number\n"; 
		}
	}

        $binary_var = int2bin($var);
	$final = $binary_inst.$binary_var;

	&output;


}

sub output {
###############################
#
# This is the output function.  It writes the binary code to the output file.
#
###############################
 
#       print "Input: $inst\n";
#       print "Length of input: $inst_length\n";
#	print "Inst in binary: $binary_inst\n";
#	print "Var: $var\n";
#       print "Var in binary: $binary_var\n";
#	print "Final: $final\n";
	print OUTPUT "$final\n";

}

sub int2bin { 
############################### 
# 
# This converts a decimal integer to a binary number.  It uses one of the 
# methods we learned in class, dividing by two and examining remainders. 
# Since the conversion doesn't always result in a binary number of the
# correct number of digits, this also prepends the appropriate "0"s to make
# it correct. 
#
# This function takes one variable, an integer.
#
# This function returns a binary number.
#
###############################	


	($int) = @_;
	$bin = "";
	while ($int != 0) {
		$temp = ($int / 2);
		if ($temp != int $temp) {
			$bin = "1" . $bin;
		} else {
			$bin = "0" . $bin;
		}
		$int = int $temp;
	}

        $places = $inst_size - length($bin) - $inst_length;

        for ($temp = 0; $temp < $places; $temp++) {
		$bin = "0".$bin;
	}

	return $bin;
}

      


Last modified: Wednesday, 05-Mar-2003 23:41:35 EST