Pages

                           

Tuesday, January 4, 2011

Multiplication In Hack Assembly Language

This is a HACK Assembly language program to multiply two numbers. The numbers reside in the memory location of Register R0 and R1. This numbers are fetched and manipulated and the result is obtained.
This project is to be done in chapter 4 of the book "Elements Of Computing System". 

The assembly code for Multiplication of two numbers is as shown below:

@i
M=1
(LOOP)
@i
D=M
@R1
D=D-M
@END
D;JGT
@R0
D=M
@mul
M=M+D
@i
M=M+1
@LOOP
0;JMP
(END)
@END
0;JMP

HACK ALU

This is the implementation of Hack Arithmetic And Logic Unit (ALU) of chapter 2. ALU is implemented by using the previously built gates of chapter 1 and chapter 2 . ALU consists of 8 inputs and 3 outputs. Depending on the value of zx, nx, zy, ny, f and no all the operations of ALU are performed on input x and y.

The HDL code for ALU is as shown below:

CHIP ALU{ 
IN x[16],y[16],zx,nx,zy,ny,f,no;
       OUT out[16],zr,ng;

    PARTS:
 Mux16(a=x,b[1..15]=false,sel=zx,out=w2);
 Not16(in=w2,out=w3);
         Mux16(a=w2,b=w3,sel=nx,out=x1);

        Mux16(a=y,b[1..15]=false,sel=zy,out=w5);
        Not16(in=w5,out=w6);
        Mux16(a=w5,b=w6,sel=ny,out=y1);
Add16(a=x1,b=y1,out=add1);
And16(a=x1,b=y1,out=or1);
Mux16(a=or1,b=add1,sel=f,out=out1);

Not16(in=out1,out=out2);
Mux16(a=out1,b=out2,sel=no,out=out,out=test,out[0..7]=fstout,out[8..15]=sndout);
And16(a=test,b[15]=true,b[0..14]=false,out[15]=ng);
Or8Way(in=fstout,out=orout1);
Or8Way(in=sndout,out=orout2);
Or(a=orout1,b=orout2,out=orout3);
Not(in=orout3,out=zr);
}

Monday, January 3, 2011

AND using NAND only

Implementation of AND gate using NAND gate only.
This is the first Project of  the chapter 1.

CHIP And
{
        IN a, b;
OUT out;  

PARTS:
Nand(a=a,b=b,out=x);
Not(in=x,out=out);

}

The above is the Hardware Description Language used to implement AND gate.

Logic Circuit

The main reason for simulating Logic Circuit in Python is to understand the concept of Object Oriented Programming and the power of Inheritance.

A couple of Python classes is used to simulate the behavior of logic circuits. The program consists of,

1) A base class LC (logic circuit) which will be subclassed to actual gates and other circuits.

2) A second class, Connector, will be used to provide inputs and outputs to the logic circuits. 

3) And an output connectors connect method which will simulate the wiring of LC's to one another.

In this, 3 basic logic gates AND , OR , NOT are first build. Then using the 3 basic gates a NAND, XOR, NOR, XNOR gates are build.

Then later the half adder and full adder circuits are also build using the logic gates. 

The entire program is as follows:

class Connector :
    
    def __init__ (self, owner, name, activates=0, monitor=0) :
        self.value = None
        self.owner = owner
        self.name  = name
        self.monitor  = monitor
        self.connects = []
        self.activates= activates   # If true change kicks evaluate function

    def connect (self, inputs) :
        if type(inputs) != type([]) : inputs = [inputs]
        for input in inputs : self.connects.append(input)


    def set (self, value) :
        if self.value == value : return      # Ignore if no change
        self.value = value
        if self.activates : self.owner.evaluate()
        if self.monitor :
            print "Connector %s-%s set to %s" % (self.owner.name,self.name,self.value)
        for con in self.connects : con.set(value)

class LC :

    # Logic Circuits have names and an evaluation function defined in child classes
    # They will also contain a set of inputs and outputs

    def __init__ (self, name) :
        self.name = name
    def evaluate (self) : return
            
class Not (LC) :         # Inverter. Input A. Output B.
    def __init__ (self, name) :
        LC.__init__ (self, name)
        self.A = Connector(self,'A', activates=1)
        self.B = Connector(self,'B')
    def evaluate (self) : self.B.set(not self.A.value)

class Gate2 (LC) :         # two input gates. Inputs A and B. Output C.
    def __init__ (self, name) :
        LC.__init__ (self, name)
        self.A = Connector(self,'A', activates=1)
        self.B = Connector(self,'B', activates=1)
        self.C = Connector(self,'C')

class And (Gate2) :       # two input AND Gate
    def __init__ (self, name) :
        Gate2.__init__ (self, name)
    def evaluate (self) : self.C.set(self.A.value and self.B.value)

class Or (Gate2) :         # two input OR gate.
    def __init__ (self, name) :
        Gate2.__init__ (self, name)
    def evaluate (self) : self.C.set(self.A.value or self.B.value)

class Xor (Gate2) :
    def __init__ (self, name) :
        Gate2.__init__ (self, name)
        self.A1 = And("A1") 
        self.A2 = And("A2")
        self.I1 = Not("I1")
        self.I2 = Not("I2")
        self.O1 = Or ("O1")
        self.A.connect    ([ self.A1.A, self.I2.A])
        self.B.connect    ([ self.I1.A, self.A2.A])
        self.I1.B.connect ([ self.A1.B ])
        self.I2.B.connect ([ self.A2.B ])
        self.A1.C.connect ([ self.O1.A ])
        self.A2.C.connect ([ self.O1.B ])
        self.O1.C.connect ([ self.C ])

class HalfAdder (LC) :         # One bit adder, A,B in. Sum and Carry out
    def __init__ (self, name) :
        LC.__init__ (self, name)
        self.A = Connector(self,'A',1)
        self.B = Connector(self,'B',1)
        self.S = Connector(self,'S')
        self.C = Connector(self,'C')
        self.X1= Xor("X1")
        self.A1= And("A1")
        self.A.connect    ([ self.X1.A, self.A1.A])
        self.B.connect    ([ self.X1.B, self.A1.B])
        self.X1.C.connect ([ self.S])
        self.A1.C.connect ([ self.C])

class FullAdder (LC) :         # One bit adder, A,B,Cin in. Sum and Cout out
    def __init__ (self, name) :
        LC.__init__ (self, name)
        self.A    = Connector(self,'A',1,monitor=1)
        self.B    = Connector(self,'B',1,monitor=1)
        self.Cin  = Connector(self,'Cin',1,monitor=1)
        self.S    = Connector(self,'S',monitor=1)
        self.Cout = Connector(self,'Cout',monitor=1)
        self.H1= HalfAdder("H1")
        self.H2= HalfAdder("H2")
        self.O1= Or("O1")
        self.A.connect    ([ self.H1.A ])
        self.B.connect    ([ self.H1.B ])
        self.Cin.connect  ([ self.H2.A ])
        self.H1.S.connect ([ self.H2.B ])
        self.H1.C.connect ([ self.O1.B])
        self.H2.C.connect ([ self.O1.A])
        self.H2.S.connect ([ self.S])
        self.O1.C.connect ([ self.Cout])


class Nor(Gate2):
def __init__(self,name):
Gate2.__init__(self,name)
self.O1=Or("O1")
self.N1=Not("N1")
self.A.connect([self.O1.A])
self.B.connect([self.O1.B])
self.O1.C.connect([self.N1.A])
self.N1.B.connect([self.C])
class Xnor(Gate2):
def __init__(self,name):
Gate2.__init__(self,name)
self.A1=And('A1')
self.A2=And('A2')
self.O1=Or('O1')
self.N1=Not('N1')
self.N2=Not('N2')
self.A.connect([self.A1.A,self.N2.A])
self.B.connect([self.A1.B,self.N1.A])
self.N1.B.connect([self.A2.A])
self.N2.B.connect([self.A2.B])
self.A1.C.connect([self.O1.A])
self.A2.C.connect([self.O1.B])
self.O1.C.connect([self.C])
def main():
gate=input('Enter the Logic Gate( And / Or / Not / Xor / Nor / Xnor ):')
in1=input('Enter the value for A:')
        in2=input('Enter the value for B:')

a=gate('A1')
a.C.monitor=1 
a.A.set(in1)
a.B.set(in2)
main()

Huffman Coding



Huffman coding algorithm is a minimal variable-length character coding algorithm based on the frequency of each character.The algorithm was developed by David Huffman.  This is called "lossless" compression and is different from "lossy" compression used in audio and video files where the exact original cannot be reproduced. This is used in programs like Winzip, gzip, stuffit etc. The secret of compressing data lies in the fact that not all characters are equally common. For instance, in typical English text the letter 'e' is much more common than the letter 'z'. In fact there are roughly 70 'e's for every 'z'. If we could encode the letter 'e' with less than the usual 8 bits and in exchange let the letter 'z' be take more.


Huffman Coding program consists of 7 functions. The functions is explained below:


1. Determining Relative frequencies


The function input is a string. A dictionary of letters along with their number of occurrence is created.



def Freq(stri):

freq = {}

for ch in stri:

freq[ch] = freq.get(ch,0)+1

print freq

2. Sorting list of tuples


This function builds and sorts a list of tuples. This list will be the input for the main Huffman algorithm.



def SortFreq(freq):

tuples=[]

for all in freq:

tuples.append((freq[all],all))

tuples.sort()

print tuples


3. Building a Tree


This function pops two elements from the front of the list and combined into a new element.  These 2 elements will have the least frequencies. The frequency of the new branch point is simply the sum of the frequencies of its two parts. Next we add this new element onto the list and sorted to find it's new position. The process is repeated until the list has a single element which represents the complete tree.



def BuildTree(tuples):

global string

while len(tuples)>1:

leastTwo=tuple(tuples[0:2])

rest=tuples[2:]

combFreq=leastTwo[0][0]+leastTwo[1][0]

tuples=rest+[(combFreq,leastTwo)]

tuples.sort()

print tuples 



4. Trimming of the frequencies 



This function trims the frequencies thus resulting in tuples containing only letters with no corresponding frequencies.



def Trim(tuples):

p=tuples[1];

if type(p)==type(""):

return p

else: 

return (Trim(p[0]),Trim(p[1])) 



5. Assigning codes to the Characters


This function assigns codes to the letters in the tree keeping track of the left and right turns in the variable "pat". There is a global dictionary "codes" which will be filled in along the way.




def Coding(node,pat=""):

global code

if type(node)==type(""):

code[node] = pat


else:

 Coding(node[0],pat+'0')

 Coding(node[1],pat+'1')

return code


6. Encoding a Text Stream



This function looks up the bit string for each character from the coded dictionary and replace it..



def encoding(str):

global code

result=""

for let in str:

result+=code[let]

return result 


7. Decoding a Text Stream 


This function does the reverse process of encodeing. In this each "zero" in the bit stream means a left turn up the tree, each "one" a right turn. When a leaf is reached, its character is sent to the output and we restart at the base of the tree for the next character.



def decoding(tree,str):

result=""

p=tree

for num in str:

if num=='0':

p=p[0]

else:

p=p[1]

if type(p)==type(""):

result+=p

p=tree

return result



Output:


This program turns the original string "aaabccdeeeeeffg" into 44 bits that we represent with "00000010010100101010111111111101101110111000". The original text at one byte per character requires 120 bits.