[Brandon University crest][The famous "Halfway Tree" of the Prairies, between Winnipeg and Brandon]

Micro Programmable Computer

Site Map
MPC Home
Program Structure
Computer
Macro Assembler
Micro Assembler
Example
Diagram
Download

 

 

Program Structure

The program consists of device classes derived from base classes Store and Source along with utility classes MacroAssembler, MicroAssembler and Computer. Computer contains a collection of stores and sources connected together to form a sequential circuit that simulates a digital computer. MacroAssembler provides a way to initialize program and data memory while MicroAssembler provides a way to initialize the micro-control memory. Computer also contains an iterative algorithm to run the simulation.

There are three categories of device classes: sequential, function and transformer. A sequential device has state that changes in reaction to high and low clock transitions. Functions and transformers represent combinational circuits. 

A source is any class derived from Source. The subclass must provide an implementation of eval(). A source represents any object in Figure 8-26 that is at the origin of an arrow. Function and transformer classes are derived from Source.

A store is any class derived from Store. The subclass must provide implementations of clkHigh() and clkLow(). A store represents any object in Figure 8-26 that has persistence.

Some classes are both stores and sources. These are the classes that maintain state from one clock cycle to the next. They are the objects shown with a blue background in Figure 8-26, namely PC, IR, CAR, Register File, and Memory. Control Memory, being a ROM, is just a Store.

In execution, the inputs to stores receive data from the output of another store through a series of intermediate sources. For example, in the diagram, the input to CAR is taken from a 2-to-1 multiplexor, "MUX C", that selects between  the opcode field of the IR and the NA field of the control word. The first data input is a FieldExtractor Source that extracts bits 20 through 27 of the control word. The second data input is an Extractor Source that extracts bits 9 through 15 of the IR. The selector input of "MUX C" is the output from an 8-to-1 multiplexor, "MUX S". The data inputs are stored as an array of sources and the selector input selects one of them to evaluate.

Another example is the DA input of the register file. A FieldExtractor is constructed for the DR field of IR and another Extractor is constructed for the TD field of ControlMemory. a Concatenator is constructed from these two Extractors and used as the DA source for RegFile.

Class Hierarchy

Transformers (Combinational)

Registers (Persistent)

Register File (Persistent)


Functions (Combinational)

Stores

The run() method of Computer calls the clkHigh() method of each store and then calls the clkLow() method. A micro-branch to 255 halts the computer.

for (;;) {
	m_PC->clkHigh();
	m_IR->clkHigh();
	m_reg->clkHigh();
	m_mem->clkHigh();
	m_CAR->clkHigh();

	m_PC->clkLow();
	m_IR->clkLow();
	m_reg->clkLow();
	m_mem->clkLow();
	m_CAR->clkLow();
	cout << endl;
	if (m_CAR->eval() == 255)
		break;
}

Each store has instance variables m_latch_dataIn and m_dataOut. clkHigh() evaluates all input sources and uses them to construct a new value in m_dataIn. clkLow() copies m_dataIn to m_dataOut. This technique eliminates race conditions and obviates an iterate-to-convergence approach. The stores emulate master-slave flipflops, where the master loads on a rising clock edge and the slave stores on a falling clock edge.

Some stores have additional instance variables to augment m_dataIn. Their function will become obvious upon viewing the source code.

Sources

A source is an object that can be evaluated. A subclass of Source contains one or more instances of other sources. eval() returns an expression by composing the results of eval() for the contained instances.

Here is a summary of sources and their evals(). The class and role of member variables can be deduced from variables with names that start with m_.

Source Class eval() body
Concatenator
int low = m_low->eval();
int high = m_high->eval();
return (low & ((1 << m_lowsize) - 1)) 
   | (high << m_lowsize);
FieldExtractor
int t = m_source->eval();
return (t >> m_offset) & ((1 << m_width) - 1);
FunctionUnit
int t = m_FS->eval();
switch (t) {
   case 0:
      return m_A->eval();
      ...
   default:
      return 0;
   } 
FunctionUnitN
return m_functionUnit->eval() < 0;
FunctionUnitZ
return m_functionUnit->eval() == 0;
MUX2_1
int t = m_cSelect->eval();
return m_dIn[t]->eval();
MUX8_1
int t = m_cSelect->eval();
return m_dIn[t]->eval();
Not
return !m_dIn->eval();
One
return 1;
ROM
return m_mem[m_aIn->eval()];
RegFileB
return m_regfile->evalB();
SignExtender
int t = m_dIn->eval();
return (t << (32 - m_width)) >> (32 - m_width);
Zero
return 0;

Stores and sources can be indirectly mutually referential. Because of this, constructor arguments cannot be used to initialized member variables. Rather, a separate Create() method is provided so that construction and initialization can be programmed as separate events. 

Here is a summary of the creation arguments for sources. In the body of each Create, parameters are copied to member variables whose names are the same as those of the parameters, prefixed by m_. Parameters and members are also classified by another prefix: "d" means data, "c" means control, "a" means address.
Source Class Create() parameters
Concatenator
Create(Source *high, Source *low, int lowsize)
Counter
(char * name, Source * cLoad, Source * cIncr, Source * dIn)
FieldExtractor
Create(Source *source, int offset, int width)
FunctionUnit
Create(Source *cFS, Source *dA, Source *dB)
FunctionUnitN
Create(FunctionUnit *functionUnit)
FunctionUnitZ
Create(FunctionUnit *functionUnit)
MUX2_1
Create(char *name, Source *dIn0, Source *dIn1, Source *cSelect)
MUX8_1
Create(char *name, Source *dIn0, Source *dIn1, Source *dIn2, 
Source *dIn3, Source *dIn4, Source *dIn5, Source *dIn6, 
Source *dIn7, Source *cSelect)
Not
Create(Source *dIn)
One
Create()
RAM
Create(Source *dIn, Source *aIn, Source *cMW)
RegFile
Create(char *name, Source * cLoad, Source * dIn)
RegFileB
Create(RegFile *regfile)
Register
Create(char *name, Source * cLoad, Source * dIn)
ROM
Create(Source *aIn)
SignExtender
Create(Source *dIn, int width)
Zero
Create()

Stores, again

The eval() method for most stores is straightforward. Only the register file has a more complex method that takes the temporary register into account.
Store Class eval() body
CAR
return m_dataOut;
IR
return m_dataOut;
RAM
return m_mem[m_aIn->eval()];
PC
return m_dataOut;
RegFile
int t = m_cTASA->eval();
return m_reg[t & 8 ? 8 : t];

also, evalB()

int t = m_cTBSB->eval();
return m_reg[t & 8 ? 8 : t];

However, updates are less straightforward.
Store Class clkHigh()  clkLow() 
Counter
if (m_cLoad->eval()) {
    m_latch_dataIn = m_dIn->eval();
} else if (m_cIncr->eval()) {
    m_latch_dataIn = m_dataOut + 1;
} 
m_dataOut = m_latch_dataIn;
Register
if (m_cIL->eval())
  m_latch_dataIn = m_dIn->eval();
m_dataOut = m_latch_dataIn;
RAM
m_latch_MW = m_cMW->eval();
if (m_latch_MW) {
  m_latch_dataIn = m_dIn->eval();
  m_latch_addressIn = m_aIn->eval();
}
if (m_latch_MW)
  m_mem[m_latch_aIn] = m_latch_dataIn;
RegFile
m_latch_RW = m_cRW->eval();
if (m_latch_RW) {
    m_latch_TDDR = m_cTDDR->eval();
    m_latch_dataIn = m_dIn->eval();
}
if (m_latch_RW) {
    if (m_latch_TDDR & 8)
    m_reg[8] = m_latch_dataIn;
else
    m_reg[m_latch_TDDR] = m_latch_dataIn;
}

Here is a summary of the creation arguments for stores. Recall that parameters are assigned to member variables whose names are the same as those of the parameters, prefixed by m_. Parameters and members are also classified by another prefix: "d" means data, "c" means control, "a" means address.

Store Class Create() parameters
Counter
Create(char * name, Source * cLoad, Source * cIncr, Source * dIn)
Register
Create(char *name, Source * cLoad, Source * dIn)
RAM
Create(Source *dIn, Source *aIn, Source *cMW)
RegFile
Create(Source *dIn, Source *cRW, Source *cTDDR, 
   Source *cTASA, Source *cTBSB)

Last update 10/24/03
Copyright © Gerald Dueck
[=]