//
// IndexRegister
//
// An Objective-C class for a register with the ability to load,
// increment and decrement.
//
// Operation: LOAD loads the register from the input, INC increments the
// current register value and DEC decrements the current value. These
// operations are exclusive, but the logic doesn't handle this (if more
// than one of LOAD, INC or DEC is high, then the operation is undefined).
// the register asserts its output on OUT.
//


#import "IndexRegister.h"


@implementation IndexRegister


- initNumBits:(int)nbits
	load:loadnode					// Node with LOAD signal.
	inc:incnode					// Node with INCREMENT signal.
	dec:decnode					// Node with DECREMENT signal.
	in:innode					// Node giving input.
	out:outnode					// Node accepting output.
{
    id		sel_low_inputs[2];
    id		sel_high_inputs[2];
    id		mux_sources[4];
    
    [super init];
    
    numbits = nbits;					// Remember number of bits.
    
    INITDEVTYPE("IndexRegister");
    
    TESTNODE("LOAD", loadnode, 1);			// Make sure the nodes have the right
    TESTNODE("INC", incnode, 1);			//   number of bits.
    TESTNODE("DEC", decnode, 1);
    TESTNODE("IN", innode, numbits);
    TESTNODE("OUT", outnode, numbits);
    
    LOAD = loadnode;					// Remember our nodes for later.
    INC = incnode;
    DEC = decnode;
    IN = innode;
    OUT = outnode;
    
    inc_out	= [[Node alloc] initNumBits:numbits];	// Allocate glue Nodes.
    dec_out	= [[Node alloc] initNumBits:numbits];
    mux_out	= [[Node alloc] initNumBits:numbits];
    sel_low_out		= [[Node alloc] initNumBits:1];
    sel_high_out	= [[Node alloc] initNumBits:1];
    
    reg_load = [[One alloc] initNumBits:1];
    reg_inc = [[Incrementor alloc] initNumBits:numbits in:OUT out:inc_out];
    reg_dec = [[Decrementor alloc] initNumBits:numbits in:OUT out:dec_out];
    reg = [[Register alloc] initNumBits:numbits in:mux_out out:OUT load:reg_load];

    sel_low_inputs[0]	= LOAD;
    sel_low_inputs[1]	= DEC;
    sel_low		= [[ORGate alloc] initNumInputs:2 inputs:sel_low_inputs
    				numBits:1 out:sel_low_out];
				
    sel_high_inputs[0]	= DEC;
    sel_high_inputs[1]	= INC;
    sel_high		= [[ORGate alloc] initNumInputs:2 inputs:sel_high_inputs
    				numBits:1 out:sel_high_out];
    
    merge_sel		= [[Merger alloc] initLowBits:1 low:sel_low_out
    				highBits:1 high:sel_high_out];
    
    mux_sources[0]	= OUT;
    mux_sources[1]	= IN;
    mux_sources[2]	= inc_out;
    mux_sources[3]	= dec_out;
    mux			= [[MUX alloc] initNumBits:numbits numselectbits:2
    				select:merge_sel sources:mux_sources out:mux_out];
    
    return self;
}


- free
{
    //
    // Free Internal Nodes:
    //
    
    [inc_out free];
    [dec_out free];
    [mux_out free];
    [sel_low_out free];
    [sel_high_out free];
    
    //
    // Free Internal Functional Units:
    //
    
    [mux free];
    [merge_sel free];
    [sel_low free];
    [sel_high free];
    [reg_load free];
    
    [reg_inc free];
    [reg_dec free];
    [reg free];
    
    return [super free];
}


- cycle
{
    [sel_low cycle];
    [sel_high cycle];
    [merge_sel cycle];
    
    [reg_inc cycle];					// Cycle the incrementer.
    [reg_dec cycle];					// Cycle the decrementer.
    [mux cycle];					// Cycle the MUX.
    
//    fprintf(stdout, "IndexRegister: MUX Output: ");
//    [mux_out dumpBinaryToFile:stdout];
//    fprintf(stdout, "  :  ");
//    [mux_out dumpHexToFile:stdout];
//    fprintf(stdout, "\n");
    
    [reg cycle];					// Cycle the register itself.
}


- reg
{
    return reg;
}


@end


//
// End of file.
//