Mixed Signal AVR Simulator       

   ECE491 Project by Engin Ipek Advisor: Bruce Land

Introduction                          High Level Design                           Results                       Netlist Files                           Listing                        Improvements

 Introduction:

Today, one of the most efficient and cost-effective methods of placing random logic in electronic equipment is using a microcontroller. Due to their high I/O capabilities, low cost, low power and off-the-shelf availability, microcontrollers find a wide range of applications in the embedded design space, from engine control systems to cellular phones, calculators and digital clocks. In many of these real-time applications, the microcontroller is used to interface to the external world in order to monitor, generate or sample analog and digital signals by interacting with other hardware. In such cases where the design contains both analog and digital signals, it is usually insufficient to simulate the analog parts using a transient analysis algorithm and the digital parts using a logic simulator. Although this approach may be adequate for a restricted number of simple circuits, in many complex systems the digital part may produce analog signals that are combined with analog signals in analog circuitry. Moreover, the digital ports might have loading effects on the analog circuitry and the analog components may affect the current sinking/sourcing capabilities of the digital components.  Having the ability to simulate such effects is an indispensable tool when making mixed-signal design decisions (eg, the effect of switching noise from a microcontroller on a sensitive scanning-tunneling microscope IrPt tip) and necessitates the implementation of such simulators for microcontrollers.

In an attempt to provide a solution to this problem, I designed a mixed signal simulator that can be used to analyze the analog, digital (gate level) and RTL level behavior of small systems built around Atmel AT90S8515 series microcontrollers for my ECE 491 project. The simulator allows the user to set up mixed-signal systems and to specify the programs to run on the microcontrollers by using a simple hardware-description language whose syntax is similar to Spice net-list format. In order to run the simulator, the user provides a net-list file listing all of the electrical connections in the system, an optional stimulus file describing external events (button pushes, received signals, noise etc.) and a hex file describing the initial state of the instruction and data memories of the microcontroller (these hex files can be easily generated from assembly files using ATMEL AVR Studio). Once these files have been provided, the simulator compiles the circuit, checks for potential problems and reports any errors. Once a circuit has been compiled successfully, the user is able to run the hex files and view the contents of the memory and the register file. It is also possible to perform DC and transient analyses on the analog circuitry, timing analysis on the logic components (CMOS, TTL etc.), and behavioral analyses on any additional systems included in the design. An RS232 terminal emulator is also implemented to model communication using the UART of the 8515. The user has the ability to edit models for new devices or to change certain parameters on the existing devices.  A summary of the devices that are provided by the simulator as library models is given below

*   Linear resistors and capacitors.

*   Ideal sources, controlled sources

*   Ideal Op-Amps

*   Diodes

*   MOSFETs (Spice Level 1 Model) and BJTs

*   Noise sources

*   Buttons

*   Logic gates and flip-flops

*   AT90S8515 series microcontrollers

*   RS232 terminal emulator

The results of the analog simulation are output in an excel file while the digital and RTL level simulation results can be viewed using GTKwave.

High Level Design:

 

The simulator was written in Java programming language. The code was organized roughly as depicted in the figure below, where each box represents a class and arrows denote the interaction of one class with another.  On each arrow, outputs of one type of object that are passed to another object as inputs are shown (eg, the parser passes an array of logic elements to class Logic). For simplicity, only the major classes and the main inputs/outputs of those classes are shown, while a complete listing of the code can be found under the listing section.

 

 

 

 


                                                                                   

                                                                                                 -Program Organization-

 

The simulation begins when the parser reads the netlist file and determines the location of the hex file containing an image of the memory at time t=0. This information is passed onto the hex-reader, which reads the hex file and loads the appropriate data and instructions into the RTL level model of the 8515. This loaded model is then given to the solver class as an input. As the parser goes through the netlist file, it also creates an array of the logic elements (logic gates and flip-flops) that are referenced by the designer. Every logic element object in this array includes the type of the element (eg, D flip-flop) and the connections to its fan-in and fan-out. This array is passed to the logic class which instantiates a logic solver based on the nodes, connections and initial inputs in the Logic Element [] array. This logic solver is then given to the Solver class as an input. Finally, the parser creates an array of analog elements with initial conditions on nodes at time t=0, and passes this array to the compiler class. The compiler generates linear models of every component for the next iteration of the simulation and uses these linear models with the initial conditions to generate a matrix equation of the form Ax=z where A is an n*n matrix (for n analog components) and z is a vector of length n. Once the logic simulator, the RTL level model of the microcontroller and the matrix equation are passed to the solver, the solver determines the dependencies between the submitted nodes and solves the matrices and logic equations for the next time step. It also advances the simulation of the microcontroller by one clock cycle. The results from the current time step are returned to the compiler, which re-generates the linear models for the next iteration and passes A and z back to the solver. This cycle goes on until the user specified simulation termination time is reached. At that point, the solver passes the values that it has stored throughout the simulation to the xls and vcd classes, which generate an excel file containing the analog results and a vcd file (to be viewed by GTKwave) containing the RTL level and digital results, respectively.

 

The non-linear equations are solved using the Newton-Raphson algorithm while the transient analysis is based on the backward-euler integration formula. At every iteration, the results for the shared nodes of all three simulations (RTL, logic and analog) are converted to the appropriate signal domain and passed as an input to the appropriate model  (eg, the digital outputs of the microcontroller that are inputs to analog circuitry are converted into analog and passed onto the analog compiler class for the next iteration). Because of the use of the backward-euler formula, only stable circuits can be successfully simulated. Hence, oscillators should be implemented using the voltage sources and not other circuits that have stability issues. The wien-bridge oscillator, for instance, will have a high damping constant associated with it and hence the simulation results will not reflect the physical reality.

 

Results:

 

The results of the simulation were found accurate to 9 decimal places when p-Spice analog simulator was taken as a reference. The microcontroller was also found to be perfectly cycle accurate in all test cases. The following circuit & corresponding results are provided as typical outcomes of the simulation, and a step-by-step explanation of writing the netlist file for this example is listed. A more detailed explanation of the netlist format is provided under the “Netlist Files” section.

 

Consider the following circuit that generates a 4.95kHz sinewave. PORTC of the microcontroller is set up to generate a new value every 1/16 of a cycle so that a total of 16 samples/cycle of the sinewave can be obtained. The output is then converted into analog using an R-2R ladder DAC and this signal is amplified by an inverting op-amp circuit of gain –2.  To illustrate the use of logic gates, the 2 least significant bits of portc are input to an and gate and the result is or’ed with bit 2 of portc.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


The netlist file describing the hardware in the schematics is provided at the right.

The first line gives the name of the hex file to be loaded into the memory. The DAC

is defined next, followed by the connections to portc and the logic gates.  The dump

 statements at the end specify the nodes whose values are to be stored into excel and

vcd files for viewing after the simulation. These nodes are also named in the body of

the dump statements to facilitate the viewing process. A more detailed explanation

of the netlist file format can be found under the netlist files section.


The C code that is running on the microcontroller is provided below. To run the simulator, this file was compiled by Code Vision AVR C Compiler with

“Intel Hex” selected as the output file format.

 

 

//Sine wave generator using C

//4.95kHz frequency

#include <90s8515.h>

//Define constants

#define prescale1 1

#define clear_on_match 8

//Sample number

unsigned char sample ; 

 

//Table of sine values

flash unsigned char sinetable[16]={0x80, 0xb1, 0xda, 0xf6, 0xff, 0xf6, 0xda, 0xb1,

                                                                                                   0x80, 0x4f, 0x26, 0x0a, 0x00, 0x0a, 0x26, 0x4f};

 

//**********************************************************

//timer 1 compare-match A ISR

interrupt [TIM1_COMPA] void cmpA_overflow(void)

  {      

  PORTC = sinetable[sample++] ; //PORTC = Next sine value

  if (sample == 16) sample=0 ;  //Go back to beginning of table if period complete

  } 

//**********************************************************

 

void main(void)

  {

            sample = 0 ;               //Initialize sample # to beginning of table

            TIMSK = 0x40 ;         //Timer 1 CompareA 

            DDRC = 0xff ;            //port C are outputs

            OCR1A = 100;           // Set up OCR1A       

            TCCR1B = prescale1 + clear_on_match ;  

            //setup clear on match

            TCNT1 = 0;   

            //turn on all interrupts

            #asm

                        sei

            #endasm

            while(1){}       //Do nothing, wait for ISR to be called

  }

 

 

The results of the simulation are shown below. The plots are taken directly form the excel file generated by the simulator, where the node names agree with the definitions in the dump statements. The plot on the left shows the output of the DAC and the output of the Op Amp vs. time. The microcontroller spends the initial 3600 cycles running the boot code and consequently portc does not change during this time. The plot on the right shows the gain of the Op

Amp. As expected, the gain is equal to –2 and the amplifier is perfectly linear since it is an ideal Op Amp (R-squared = 1, y= -2x on the plot).

 

 

 

 

 

 

 

 

 

 


The results of the digital simulation are shown below. The top two rows show the values of portc and the output of the or gate, respectively.

 

 


 

 


The performance of the simulator was evaluated based on the ratio of the simulation time to real-time. Although the non-linear transient analysis used in the simulator has O(n2) asymptotic complexity, linear circuits such as the one shown above can be simulated reasonably fast. Since the program spends a significant amount of its time (30% for the example above) generating the output files, reducing the number of output nodes that the simulator saves (using dump statements) significantly improves performance. Hence, for fast simulations, only essential signals should be stored. The performance of the simulator for the sinewave generator example is shown below. As indicated by the plot, the simulator is approximately 700 times slower with respect to real time. For testing typical microcontroller – based designs, this performance is adequate. For instance, it takes roughly 1.5 minutes to simulate 1 million instructions of the sinewave generator, where 10000 instructions are enough to see 4 full cycles of the sinewave.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


           

Netlist Files:

As shown in the sinewave generator example, every netlist file begins with a statement of the form “MCU filename.hex” where filename.hex is the hex file that contains a memory image of the initial processor state. This statement is followed by a description of the connections in the circuit. In order to make these connections, the user assigns a unique number from 1 to n to each node, where n is the number of nodes in the circuit (excluding GND). By default, node 0 always corresponds to ground, but aside from this convention the user is free too select any number to correspond to any node. Connections are specified by listing the element name, the input and output nodes and the parameters related to the operation of the element. For instance, “R 1 2 1000”

places a 1k ohm resistor between nodes 1 and 2. A full list of the parameters that must be specified for every element is provided below. Connections to the microcontroller are made by statements of the form “PORT node_number IO_address bit_number” where node_number specifies the number assigned by the user, IO_address gives the address of the port and bit_number shows which bit of the port to connect. To store the values of any nodes, registers or memory locations and view them after the simulation, DUMP, DUMPANALOG and DUMPLOGIC statements are used. DUMP statement is used for the microcontroller, DUMPANALOG is used for analog signals and DUMPLOGIC is used for logic signals. These statements have the following general forms:

 

DUMP name1 memAddr1 name2 memAddr2 … end where “name1….N” is any string chosen by the user and memAddr is the memory address of the specific register/memory location that the user wants to view. The VCD file uses name1… nameN when displaying the results.  Since there is no memory address for the PC, the memAddr field should be “PC” when storing the PC (eg, DUMP mcuPC PC end).

 

DUMPANALOG name1 node1 name2 node2 … end where “name1…N” is any string chosen by the user and “node1…N” corresponds to the node number specified by the user.

 

DUMPLOGIC’s format is identical to DUMPANALOG.

 

Below is a list of the circuit elements supported:

 

R node1 node2 resistance (ohms)

C node1 node2 capacitance (F)

VDC neg_terminal pos_terminal voltage (V)

VAC neg_terminal pos terminal amplitude (V) freq (Hz) type (sine or cos or triangle or pulse)

VCCS neg_terminal pos_terminal neg_terminal_reference pos_terminal_reference coefficient

VCVS neg_terminal pos_terminal neg_terminal_reference pos_terminal_reference coefficient 

CCCS  neg_terminal pos_terminal neg_terminal_reference pos_terminal_reference coefficient

CCVS neg_terminal pos_terminal neg_terminal_reference pos_terminal_reference coefficient

DIODE neg_terminal pos_terminal area

NMOS source drain gate W L K’ Vt

PMOS source drain gate W L K’ Vt

NPN    collector emitter base alfaF alfaR Is Vt

PNP    collector emitter base alfaF alfaR Is Vt

OPAMP  pos_terminal neg_terminal output_terminal pos_supply_voltage(V) neg_supply_voltage(V)

PORT node_number IO_address bit_number

AND node1 node2 node_out

OR   node1 node2 node_out

DFF node_in, node_out, CLK

BUTTON node1 node2 stimulus_file_name button_name

VRANDOM neg_terminal pos_terminal stimulus_file_name vrandom_name

 

Buttons and random voltage sources have stimulus files associated with them. At each simulation step, the values for the buttons and random voltage

Sources are read from these files. An example stimulus file is provided below, assuming that button b1 and random voltage source v1 have been declared and tied to this stimulus file in the netlist:

 

#0

b1 0

v1 0

#5

b1 1

#10

b1 0

v1 2.45

end

 

In this example, the button is off and the random voltage source is outputting 0 volts at cycle 0 (cycle # of the mcu). At cycle 5, b1 turns on. At cycle 10, b1 turns off and v1 outputs 2.45 volts.

Improvements:

Given enough time, the simulator could easily be extended to handle multiple microcontrollers. Frequency domain analysis could also be implemented and more library models could be created.

Listing:

Below is a listing of the code that can be compiled with any standard Java compiler.

AT90S8515

Compiler

Element

HexReader

Logic

LogicElement

Parser

Solver

VCD

XLS

AT90S8515:

package avrsimmx;

 

/**

 * Title: AVRSimto

 * Description: Mixed Signal AVR Simulatorsyste

 * Copyright: Copyright (c) 2002R

 * Company: Cornell University

 * @author Engin Ipek

 * @version 1.0S

 */

 

public class AT90S8515 {

//Power down mode

boolean pwrDownMode = false;

 

//Idle mode

boolean idleMode = false;

 

//WatchDog timer Reset Signal

boolean wReset = false;

 

//# of CPU cycles passed so far

long cycleNum = 0;

 

//Skip current instruction

private boolean skip = false;

 

//Program counter

private int PC= 0;

 

//Stack Pointer

private int stackPtr = 0;

 

//Current Instruction fetched form instruction memory

private short instr = 0;

 

//IO Register File

byte[] regFileIO = new byte[64];

 

//General purpose working register file

byte[] regFile = new byte[32];

 

//Internal SRAM

byte[] SRAM = new byte[512];

 

//FLASH Program Memory

short[] FLASH = new short[0xfff];

 

//TCNT0 & TCNT1 Prescalers

int prescaler0 = 0;

int prescaler1 = 0;

 

int inc0 = 0;

int inc1 = 0;

//Top value for PWM

public int top = 0;

 

//Count Direction for PWM

//Counts up if true, down if false

public boolean countUp = true;

 

//Clear Counter1 (following a Compare Match)

public boolean clrTimer1 = false;

 

//Last cycle number where a timer was reset

long resetCycle0 = 0;

long resetCycle1 = 0;

 

//Value of TCNT0 before the instruction is executed

public byte TCNT0Init = 0;

 

//Value of cycleNum before the instruction is executed

public long cycleNumInit = 0;

 

//Value of TCCR0 before the instruction is executed

public byte TCCR0Init = 0;

 

//Value of prescaler0 & prescaler1 before the instruction is executed

public int prescaler0Init = 0;

public int prescaler1Init = 0;

//Value of TCNT1 before the instruction is executed

public int TCNT1Init = 0;

 

//Value of TCCR1A & TCCR1B before the instruction is executed

public byte TCCR1AInit = 0;

public byte TCCR1BInit = 0;

 

//Value of OCR1AH and OCR1AL before the instruction is executed

public byte OCR1AHInit = 0;

public byte OCR1ALInit = 0;

public int OCR1AInit = 0;

 

//OCR1A written for the first time

public boolean OCR1AWritten = false;

 

//Execute current instruction before jumping to ISR

public boolean waitForISR_TCNT0_OVF = true;

public boolean waitForISR_TCNT1_OVF = true;

public boolean waitForISR_TCNT1_COMPA = true;

public boolean waitForISR_TCNT1_COMPB = true;

//Execute current instruction before updating TCNT0

//when prescaler0 changes

public boolean waitForPrescaler0 = true;

 

//clrTimer1 Set to High

public boolean clrTimer1Set = false;

//Value of TCNT1

int TCNT1 = 0;

 

//Aliases for the registers

//byte SREG = regFileIO[0x3f];

//byte SPH = regFileIO[0x3e];

//byte SPL = regFileIO[0x3d];

//byte GIMSK = regFileIO[0x3b];

//byte GIFR = regFileIO[0x3a];

//byte TIMSK = regFileIO[0x39];

//byte TIFR = regFileIO[0x38];

//byte MCUCR = regFileIO[0x35];

//byte TCCR0 = regFileIO[0x33];

//byte TCNT0 = regFileIO[0x32];

//byte TCCR1A = regFileIO[0x2f];

//byte TCCR1B = regFileIO[0x2e];

//byte TCNT1H = regFileIO[0x2d];

//byte TCNT1L = regFileIO[0x2c];

//byte OCR1AH = regFileIO[0x2b];

//byte OCR1AL = regFileIO[0x2a];

//byte OCR1BH = regFileIO[0x29];

//byte OCR1BL = regFileIO[0x28];

//byte ICR1H = regFileIO[0x25];

//byte ICR1L = regFileIO[0x22];

//byte WDTCR = regFileIO[0x21];

//byte EEARH = regFileIO[0x1f];

//byte EEARL = regFileIO[0x1e];

//byte EEDR = regFileIO[0x1d];

//byte EECR = regFileIO[0x1c];

//byte PORTA = regFileIO[0x1b];

//byte DDRA = regFileIO[0x1a];

//byte PINA = regFileIO[0x19];

//byte PORTB = regFileIO[0x18];

//byte DDRB = regFileIO[0x17];

//byte PINB = regFileIO[0x16];

//byte PORTC = regFileIO[0x15];

//byte DDRC = regFileIO[0x14];

//byte PINC = regFileIO[0x13];

//byte PORTD = regFileIO[0x12];

//byte DDRD = regFileIO[0x11];

//byte PIND = regFileIO[0x10];

//byte SPDR = regFileIO[0x0f];cycl

//byte SPSR = regFileIO[0x0e];

//byte SPCR = regFileIO[0x0d];

//byte UDR = regFileIO[0x0c];

//byte USR = regFileIO[0x0b];

//byte UCR = regFileIO[0x0a];

//byte UBRR = regFileIO[0x09];

//byte ACSR = regFileIO[0x08];

 

//PORTS & PINS

public byte Pa;

public byte Pb;

public byte Pc;

public byte Pd;

 

//Pins

//PINA

public boolean PA0 = false;

public boolean PA1 = false;

public boolean PA2 = false;

public boolean PA3 = false;

public boolean PA4 = false;

public boolean PA5 = false;

public boolean PA6 = false;

public boolean PA7 = false;

 

//PINB

public boolean PB0 = false;

public boolean PB1 = false;

public boolean PB2 = false;

public boolean PB3 = false;

public boolean PB4 = false;

public boolean PB5 = false;

public boolean PB6 = false;

public boolean PB7 = false;

 

//PINC

public boolean PC0 = false;

public boolean PC1 = false;

public boolean PC2 = false;

public boolean PC3 = false;

public boolean PC4 = false;

public boolean PC5 = false;

public boolean PC6 = false;

public boolean PC7 = false;

 

//PIND

public boolean PD0 = false;

public boolean PD1 = false;

public boolean PD2 = false;

public boolean PD3 = false;

public boolean PD4 = false;

public boolean PD5 = false;

public boolean PD6 = false;

public boolean PD7 = false;

 

//Other pins

public boolean GND    = false;

public boolean VCC    = false;

public boolean XTAL1  = false;

public boolean XTAL2  = false;

public boolean ICP    = false;

public boolean ALE    = false;

public boolean _RESET = false;

public boolean OC1B   = false;

 

//Aliases for pins

 

//Simulator

public void run() {

 

// while(true){

  //*************PORTS & PINS***********//

  //Handle PORTA & PINA

  for(int i = 0; i<8; i++){

    //regFileIO[0x1b]

    if(getBit(regFileIO[0x1a],i))

      Pa = setBit(Pa,i,getBit(regFileIO[0x1b],i));

    //PINA

    else

      regFileIO[0x19]=setBit(regFileIO[0x19],i,getBit(Pa,i));

  }

  //Handle PORTB & PINB

  for(int i = 0; i<8; i++){

    //PORTB

    if(getBit(regFileIO[0x17],i))

      Pb = setBit(Pb,i,getBit(regFileIO[0x18],i));

    //PINA

    else

      regFileIO[0x16]=setBit(regFileIO[0x16],i,getBit(Pb,i));

  }

  //Handle PORTC & PINC

  for(int i = 0; i<8; i++){

    //PORTC

    if(getBit(regFileIO[0x14],i))

      Pc = setBit(Pc,i,getBit(regFileIO[0x15],i));

    //PINA

    else

      regFileIO[0x13]=setBit(regFileIO[0x13],i,getBit(Pc,i));

  }

  //Handle PORTD & PIND

  for(int i = 0; i<8; i++){

    //PORTD

    if(getBit(regFileIO[0x11],i))

      Pd=setBit(Pd,i,getBit(regFileIO[0x12],i));

    //PIND

    else

      regFileIO[0x10]=setBit(regFileIO[0x10],i,getBit(Pd,i));

  }

   //Store the value of cycleNum before executing the instruction*********************TRY W/o DEBUG

//  cycleNumInit = cycleNum;

  //*************INTERRUPTS**************//

  //Handle RESET

  if(_RESET == false){

  //  PC = 0;

  }

 

  //Handle Timer1_COMPA interrupt

  if(getBit(regFileIO[0x39],6) && getBit(regFileIO[0x38],6)){

    //I-bit is set

    if(getBit(regFileIO[0x3f],7)){

      //Store PC +1 in Stack

        SRAM[stackPtr-96] = (byte)(((PC  ) & 0x0000ff00) >>> 8);

 

        SRAM[stackPtr-96 - 1] = (byte)(((PC  ) & 0x0000ff));

        //Update stack pointer

        stackPtr = stackPtr - 2;

        regFileIO[0x3e] = (byte) ((stackPtr & 0x0000ff00) >>> 8);

        regFileIO[0x3d] = (byte) (stackPtr & 0x000000ff);

      PC = 4;

      //Clear OCF1A

      regFileIO[0x38]=setBit(regFileIO[0x38],6,false);

      //Clear the I-bit

      regFileIO[0x3f]=setBit(regFileIO[0x3f],7,false);

      //8 cycles to jumpt to ISR

      cycleNum = cycleNum+3;

      //Update TCNT1

      TCNT1 = TCNT1 + (3/prescaler1);

      regFileIO[0x2c] = (byte)(TCNT1);

      regFileIO[0x2d] = (byte)(TCNT1>>>8);

 

    }

  }

  //Handle Timer1_COMPB interrupt

  if(getBit(regFileIO[0x39],5) && getBit(regFileIO[0x38],5)){

    //I-bit is set

    if(getBit(regFileIO[0x3f],7)){

      PC = 5;

      //Clear OCF1A

      regFileIO[0x38]=setBit(regFileIO[0x38],5,false);

      //Clear the I-bit

      regFileIO[0x3f]=setBit(regFileIO[0x3f],7,false);

    }

  }

  //Handle Timer1_OVF Interrupt

  else if(getBit(regFileIO[0x39],7)&&getBit(regFileIO[0x38],7)){

       //I-bit is set

       if(getBit(regFileIO[0x3f],7)){

        //Store PC +1 in Stack

        SRAM[stackPtr-96] = (byte)(((PC  ) & 0x0000ff00) >>> 8);

 

        SRAM[stackPtr-96 - 1] = (byte)(((PC  ) & 0x0000ff));

        //Update stack pointer

        stackPtr = stackPtr - 2;

        regFileIO[0x3e] = (byte) ((stackPtr & 0x0000ff00) >>> 8);

        regFileIO[0x3d] = (byte) (stackPtr & 0x000000ff);

        //Clear TOV7

        regFileIO[0x38]=setBit(regFileIO[0x38],7,false);

        //Clear the I-bit

        regFileIO[0x3f]=setBit(regFileIO[0x3f],7,false);

        //8-Cycles necessary to vector to the ISR

        cycleNum= cycleNum+3;

        PC = 6;

        //Update TCNT1

        TCNT1 = TCNT1 + (3/prescaler1);

        regFileIO[0x2c] = (byte)(TCNT1);

        regFileIO[0x2d] = (byte)(TCNT1>>>8);

      }

  }

 

  //Handle Timer0_OVF Interrupt

  else if(getBit(regFileIO[0x39],1)&&getBit(regFileIO[0x38],1)){

 

        //I-bit is set

        if(getBit(regFileIO[0x3f], 7)){

 

          //Store PC +1 in Stack

          SRAM[stackPtr-96] = (byte)(((PC  ) & 0x0000ff00) >>> 8);

 

          SRAM[stackPtr-96 - 1] = (byte)(((PC  ) & 0x0000ff));

          //Update stack pointer

          stackPtr = stackPtr - 2;

          regFileIO[0x3e] = (byte) ((stackPtr & 0x0000ff00) >>> 8);

          regFileIO[0x3d] = (byte) (stackPtr & 0x000000ff);

          PC = 7;

          //Clear TOV0

          regFileIO[0x38]=setBit(regFileIO[0x38],1,false);

          //Clear the I-bit

          regFileIO[0x3f]=setBit(regFileIO[0x3f],7,false);

          //8-Cycles necessary to vector to the ISR

          cycleNum= cycleNum+3;

          //Update TCNT0

          regFileIO[0x32] = (byte)(regFileIO[0x32] + (3/prescaler0));

        }

      }

  //Store the value of cycleNum, TCNT0, TCCR0, TCNT1,TCCR1A, TCCR1B before executing the instruction

  cycleNumInit = cycleNum;

  TCNT0Init = regFileIO[0x32];

  TCCR0Init = regFileIO[0x33];

  TCCR1AInit = regFileIO[0x2f];

  TCCR1BInit = regFileIO[0x2e];

  TCNT1Init =((((int) regFileIO[0x2d]) << 8)&0x0000ff00) | (((int) regFileIO[0x2c]) & 0x000000ff);

  OCR1AHInit = regFileIO[0x2b];

  OCR1ALInit = regFileIO[0x2a];

  OCR1AInit = ((((int)OCR1AHInit)<<8)&(0x0000ff00)) | (((int)OCR1ALInit)&0x000000ff);

  //**************TIMER0**************//

  //Store previous prescaler0

  prescaler0Init = prescaler0;

  //Get prescaler0

  int cs0 = regFileIO[0x33] & 0x07;

  if(cs0 == 0)

    prescaler0 = 0;

  else if(cs0 == 1)

    prescaler0 = 1;

  else if(cs0 == 2)

    prescaler0 = 8;

  else if(cs0 == 3)

    prescaler0 = 64;

  else if(cs0 == 4)

    prescaler0 = 256;

  else if(cs0 == 5)

    prescaler0 = 1024;

 

  //**************TIMER1***************//

  //Store previous prescaler1

  prescaler1Init = prescaler1;

  //Get prescaler1

  int cs1 = regFileIO[0x2e] & 0x07;

  if(cs1 == 0)

    prescaler1 = 0;

  else if(cs1 == 1)

    prescaler1 = 1;

  else if(cs1 == 2)

    prescaler1 = 8;

  else if(cs1 == 3)

    prescaler1 = 64;

  else if(cs1 == 4)

    prescaler1 = 256;

  else if(cs1 == 5)

    prescaler1 = 1024;

 

 

  //PWM Mode Disabled

/* if((!getBit(regFileIO[0x2f],0))&&(!getBit(regFileIO[0x2f],1))){

 

 

    //Compare 1A Mode Select

    //Set the OC1A output line

    if(getBit(regFileIO[0x11],5)){

      if(getBit(regFileIO[0x2f],7) && getBit(regFileIO[0x2f],6))

        regFileIO[0x12]=setBit(regFileIO[0x12],5,true);

      else if(getBit(regFileIO[0x2f],7)&&!getBit(regFileIO[0x2f],6))

        regFileIO[0x12]=setBit(regFileIO[0x12],5,false);

      else if(!getBit(regFileIO[0x2f],7)&&getBit(regFileIO[0x2f],6))

        regFileIO[0x12]=setBit(regFileIO[0x12],5,!getBit(regFileIO[0x12],5));

    }

    //Compare 1B Mode Select

    //Set the OC1B output line

    if(getBit(regFileIO[0x2f],5) && getBit(regFileIO[0x2f],4))

        OC1B = true;

    else if(getBit(regFileIO[0x2f],5)&&!getBit(regFileIO[0x2f],4))

        OC1B = false;

    else if(!getBit(regFileIO[0x2f],5)&&getBit(regFileIO[0x2f],4))

        OC1B = !OC1B;

 

    //Clear Timer 1 if a compare match

    //occurred last cycle and the CTC1

    //bit was set

    if(clrTimer1){

      clrTimer1 = false;

      regFileIO[0x2d] = 0;

      regFileIO[0x2c] = 0;

    }

  }

*/

  //PWM Mode Enabled

 /* else{

    if((!getBit(regFileIO[0x2f],0))&&(getBit(regFileIO[0x2f],1)))

      top = 255;

    if((getBit(regFileIO[0x2f],0))&&(!getBit(regFileIO[0x2f],1)))

      top = 511;

    if((getBit(regFileIO[0x2f],0))&&(getBit(regFileIO[0x2f],1)))

      top = 1023;

 

    //Compare 1A Mode Select

    //Set the OC1A output line

    if(getBit(regFileIO[0x2f],7) && getBit(regFileIO[0x2f],6)){

      if(countUp)

        regFileIO[0x12]=setBit(regFileIO[0x12],5,true);

      else

        regFileIO[0x12]=setBit(regFileIO[0x12],5,false);

    }

    else if(getBit(regFileIO[0x2f],7)&&!getBit(regFileIO[0x2f],6)){

      if(countUp)

        regFileIO[0x12]=setBit(regFileIO[0x12],5,false);

      else

        regFileIO[0x12]=setBit(regFileIO[0x12],5,true);

    }

 

    //Compare 1B Mode Select

    //Set the OC1B output line

    if(getBit(regFileIO[0x2f],5) && getBit(regFileIO[0x2f],4)){

      if(countUp)

        OC1B = true;

      else

        OC1B = false;

    }

    else if(getBit(regFileIO[0x2f],5)&&!getBit(regFileIO[0x2f],4)){

      if(countUp)

        OC1B = false;

      else

        OC1B = true;

    }

 

    //Change Count Direction

    if((((((int) regFileIO[0x2d]) << 8)&0x0000ff00) | (((int) regFileIO[0x2c]) & 0x000000ff))==top)

      countUp = !countUp;

 

    //Count Up

    if(countUp){

      if(prescaler1 != 0){

        int temp = ((((int) regFileIO[0x2d]) << 8)&0x0000ff00) | (((int) regFileIO[0x2c]) & 0x000000ff);

        temp = (int)(temp + ((cycleNum - resetCycle1) % prescaler1));

        regFileIO[0x2d] = (byte) (temp >>> 4);

        regFileIO[0x2c] = (byte) temp;

      }

    }

    //Count Down

    else{

      if(prescaler1 != 0){

        int temp = ((((int) regFileIO[0x2d]) << 8)&0x0000ff00) | (((int) regFileIO[0x2c]) & 0x000000ff);

        temp = (int)(temp - ((cycleNum - resetCycle1) % prescaler1));

        regFileIO[0x2d] = (byte) (temp >>> 4);

        regFileIO[0x2c] = (byte) temp;

      }

    }

  }

*/

/*

  //Handle Overflows

  if((regFileIO[0x2d] == 0xff) && (regFileIO[0x2c] ==0xff))

    regFileIO[0x38]=setBit(regFileIO[0x38],7,true);

 

  if((regFileIO[0x2d] == regFileIO[0x2b]) && (regFileIO[0x2c] == regFileIO[0x2a])){

    regFileIO[0x38]=setBit(regFileIO[0x38],6,true);

    //Check the CTC1 bit

    if(getBit(regFileIO[0x2e],3))

       clrTimer1 = true;

  }

 

  if((regFileIO[0x2d] == regFileIO[0x29]) && (regFileIO[0x2c] == regFileIO[0x28])){

    regFileIO[0x38]=setBit(regFileIO[0x38],5,true);

  }

*/

  //*************************************************************//

 

  //Fetch the next instruction

  instr = FLASH[PC];

 

  //Destination (and source) register in the register file

  int Rd = (int) ((instr & 0x01f0) >>> 4);

  //Source register in the register file

  int Rr = (int) ((instr &0x000f)+((instr&0x0200)>>>5));

  //Constant data

  int K = (int) ((instr & 0x0f00) >>> 4) + (instr & 0x000f);

  //Constant address (signed)

  int k = (((int) ((instr >>> 3) & 0x003f)) << 25) >> 25;

  //Bit in the register file or I/O register

  int b = (int)(instr & 0x0007);

  //Bit in the status register

  int s = (int)((instr >>> 4) & 0x0007);

  //I/O location address

  int A = (int) ((instr >>> 4) & 0x000f);

  //Displacement for direct addressing

  int q = (int) ((instr & 0x00000007) | ((instr & 0x00000c00)>>>7) | ((instr & 0x00002000) >>> 8));

  //Result of the current instruction

  byte R = 0;

  //X,Y,Z registers

  int X = 0;

  int Y = 0;

  int Z = 0;

  X = ( ((X|regFile[27])<< 8) & (0x0000ff00))|(((int)regFile[26]) & 0x0000000ff);

  Y = ( ((Y|regFile[29])<< 8) & (0x0000ff00))|(((int)regFile[28]) & 0x0000000ff);

  Z = ( ((Z|regFile[31])<< 8) & (0x0000ff00))|(((int)regFile[30]) & 0x0000000ff);

 

  //Get current SP

  stackPtr = ((((int)regFileIO[(short)0x003e])&0x000000ff)<<8) | (((int)(regFileIO[0x3d]) & 0x0000000ff));

  //Decode and execute the instruction

  ////System.out.println("********************************BEGIN*****************************");

  ////System.out.println("TCNT0="+ regFileIO[0x32]);

  ////System.out.println("TCNT1Lo="+regFileIO[0x2c]);

  ////System.out.println("TCNT1Hi="+regFileIO[0x2d]);

  ////System.out.println("TIMSK="+ regFileIO[0x39]);

  ////System.out.println("prescaler1="+prescaler1);

  ////System.out.println("TIFR="+ regFileIO[0x38]);

  ////System.out.println("PORTC = "+regFileIO[0x15]);

  ////System.out.println("INSTR:" + instr);

  ////System.out.println("PC="+PC);

  ////System.out.println("SREG="+SREG);

  ////System.out.println("Cycle #="+cycleNum);

 /* for(int i = 0; i<32; i++){

      if(i == 16)

        //System.out.println("|R["+i+"]="+regFile[i]);

     else

       //System.out.print("|R["+i+"]="+regFile[i]);

    }

    //System.out.println();*/

  switch(instr & 0xf000){

 

 

    case 0x1000:

      //ADC (ROL is a special case of this instruction and is not

      //implemented separately

      if((getBit(instr, 11)) && (getBit(instr, 10))){

        //System.out.println("ADC");

        //Check the C flag for carry

        byte temp = 0;

        if (getBit(regFileIO[0x3f],0))

          temp = (byte)1;

 

        //Get the result of the addition

        R = (byte)(regFile[Rd] + regFile[Rr] + temp);

 

        //Update SREG

        regFileIO[0x3f]=setBit(regFileIO[0x3f],5,(getBit(regFile[Rd],3) & getBit(regFile[Rr],3)) |

                      (getBit(regFile[Rd],3) & !(getBit(R,3))) |

                      (getBit(regFile[Rr],3) & !(getBit(R,3))));

 

        regFileIO[0x3f]=setBit(regFileIO[0x3f],3,(getBit(regFile[Rd],7)&getBit(regFile[Rr],7)&!(getBit(R,7))) |

                      (!getBit(regFile[Rd],7)&!getBit(regFile[Rr],7)&(getBit(R,7))));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],1,R == (byte) 0);

        regFileIO[0x3f]=setBit(regFileIO[0x3f],0,(getBit(regFile[Rd],7) & getBit(regFile[Rr],7)) |

                      (getBit(regFile[Rd],7) & !(getBit(R,7))) |

                      (getBit(regFile[Rr],7) & !(getBit(R,7))));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^ getBit(regFileIO[0x3f],3));

 

        //Store the result in register Rd

        regFile[Rd] = R;

 

       //Increment program counter

       PC++;

       }

 

       //CP

       if((instr & 0x0c00) == 0x0400){

       //System.out.println("CP");

        //Compare the registers

        R = (byte)(regFile[Rd] - regFile[Rr]);

        //Update SREG

        regFileIO[0x3f]=setBit(regFileIO[0x3f],5,((!getBit(regFile[Rd],3))&getBit(regFile[Rr],3)) |

                       (getBit(regFile[Rr],3) & getBit(R,3)) |

                       (getBit(R,3) &(!getBit(regFile[Rd],3))));

 

        regFileIO[0x3f]=setBit(regFileIO[0x3f],3,(getBit(regFile[Rd],7) & (!getBit(regFile[Rr],7)) & (!getBit(R,7)) )  |

                      ((!getBit(regFile[Rd],7)) & getBit(regFile[Rr],7) & getBit(R,7) ) );

        regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],1, R == 0);

        regFileIO[0x3f]=setBit(regFileIO[0x3f], 0, ((!getBit(regFile[Rd], 7)) & getBit(R,7)) |

                        (getBit(R,7) & getBit(regFile[Rr],7)) |

                        (getBit(R,7) & (!getBit(regFile[Rd],7))) );

        regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^getBit(regFileIO[0x3f],3));

        //Increment PC

        PC++;

       }

 

       //CPSE

       if((instr & 0x0c00) == 0x0000){

       //System.out.println("CPSE");

        //Skip next instr if Rd = Rr

        if(regFile[Rd] == regFile[Rr])

          skip = true;

        //Update PC

        PC++;

       }

 

       //Sub

       if(getBit(instr,11) &!getBit(instr,10)){

       //System.out.println("SUB");

        //Subtract two registers

        R = (byte)(regFile[Rd] - regFile[Rr]);

        //Update SREG

        regFileIO[0x3f]=setBit(regFileIO[0x3f],5,((!getBit(regFile[Rd],3)) & getBit(regFile[Rr],3)) |

                      (getBit(regFile[Rr],3) & getBit(R,3)) |

                      (getBit(R,3) & (!getBit(regFile[Rd],3))));

 

         regFileIO[0x3f]=setBit(regFileIO[0x3f],3,(getBit(regFile[Rd],7) & (!getBit(regFile[Rr],7)) & (!getBit(R,7)) )  |

                      ((!getBit(regFile[Rd],7)) & getBit(regFile[Rr],7) & getBit(R,7) ) );

        regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],1, R == 0);

        regFileIO[0x3f]=setBit(regFileIO[0x3f], 0, ((!getBit(regFile[Rd], 7)) & getBit(R,7)) |

                        (getBit(R,7) & getBit(regFile[Rr],7)) |

                        (getBit(R,7) & (!getBit(regFile[Rd],7))) );

         regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^getBit(regFileIO[0x3f],3));

        //Place result in Rd

        regFile[Rd] = R;

        //Update PC

        PC++;

       }

 

    break;

 

    case 0x0000:

    //ADD (LSL is a spcial case of this instruction

    if((getBit(instr, 11)) && (getBit(instr, 10))){

    //System.out.println("ADD");

      R = (byte) (regFile[Rd] + regFile[Rr]);

    //Update SREG

        regFileIO[0x3f]=setBit(regFileIO[0x3f],5,(getBit(regFile[Rd],3) & getBit(regFile[Rr],3)) |

                      (getBit(regFile[Rd],3) & !(getBit(R,3))) |

                      (getBit(regFile[Rr],3) & !(getBit(R,3))));

 

        regFileIO[0x3f]=setBit(regFileIO[0x3f],3,(getBit(regFile[Rd],7)&getBit(regFile[Rr],7)&!(getBit(R,7))) |

                      (!getBit(regFile[Rd],7)&!getBit(regFile[Rr],7)&(getBit(R,7))));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],1,R == (byte) 0);

        regFileIO[0x3f]=setBit(regFileIO[0x3f],0,(getBit(regFile[Rd],7) & getBit(regFile[Rr],7)) |

                      (getBit(regFile[Rd],7) & !(getBit(R,7))) |

                      (getBit(regFile[Rr],7) & !(getBit(R,7))));

        regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^ getBit(regFileIO[0x3f],3));

        //Store the result in register Rd

        regFile[Rd] = R;

 

       //Increment program counter

       PC++;

    }

 

    //CPC

    if((!getBit(instr,11))&getBit(instr,10)){

    //System.out.println("CPC");

    byte temp = 0;

    if(getBit(regFileIO[0x3f],0))

      temp =1;

    R = (byte)(regFile[Rd] - regFile[Rr] - temp);

    //Update SREG

    regFileIO[0x3f]=setBit(regFileIO[0x3f],5,((!getBit(regFile[Rd],3)) & getBit(regFile[Rr],3)) |

                      (getBit(regFile[Rr],3) & (getBit(R,3))) |

                      ((!getBit(regFile[Rd],3)) & (getBit(R,3))));

 

    regFileIO[0x3f]=setBit(regFileIO[0x3f],3,(getBit(regFile[Rd],7)&(!getBit(regFile[Rr],7))&!(getBit(R,7))) |

                  (!getBit(regFile[Rd],7)&getBit(regFile[Rr],7)&(getBit(R,7))));

    regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

    regFileIO[0x3f]=setBit(regFileIO[0x3f],1,(R == (byte) 0)& getBit(regFileIO[0x3f],1));

    regFileIO[0x3f]=setBit(regFileIO[0x3f],0,((!getBit(regFile[Rd],7)) & getBit(regFile[Rr],7)) |

                      ((!getBit(regFile[Rd],7)) & (getBit(R,7))) |

                      (getBit(regFile[Rr],7) & (getBit(R,7))));

    regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^ getBit(regFileIO[0x3f],3));

    //Increment PC

    PC++;

    }

 

    //NOP

    if(instr == 0){

    ////System.out.println("NOP");

    //Increment PC

    PC++;

    }

    //SBC

    if(getBit(instr,11) & !getBit(instr,10)){

    //System.out.println("SBC");

      //Subtract with carry

      byte temp = 0;

      if(getBit(regFileIO[0x3f],0))

        temp++;

      R = (byte)(regFile[Rd] - regFile[Rr] - temp);

      //Update SREG

      regFileIO[0x3f]=setBit(regFileIO[0x3f],5, ((!getBit(regFile[Rd],3)) & getBit(regFile[Rr],3)) |

                     (getBit(regFile[Rr],3)&getBit(R,3))|

                     (getBit(R,3) & !getBit(regFile[Rd],3)));

 

      regFileIO[0x3f]=setBit(regFileIO[0x3f],3, (getBit(regFile[Rd],7) & (!getBit(regFile[Rr],7)) & (!getBit(R,7))) |

                     ((!getBit(regFile[Rd],7)) &getBit(regFile[Rr],7) & getBit(R,7)));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],1,(getBit(regFileIO[0x3f],1) & (R==0)));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],0, ((!getBit(regFile[Rd],7)) & getBit(regFile[Rr],7)) |

                     (getBit(regFile[Rr],7)&getBit(R,7))|

                     (getBit(R,7) & !getBit(regFile[Rd],7)));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^ getBit(regFileIO[0x3f],3));

      //Place result in Rd

      regFile[Rd] = R;

      //Increment PC

      PC++;

    }

    break;

 

    case 0x9000:

    //ADIW

 

    if((instr & 0x0f00) == 0x0600){

    //System.out.println("ADIW");

      K = (instr & 0x000f) + ((instr & 0x00c0) >>> 2);

      //Correct the Rd field

      Rd = Rd & 0x00000003;

      //Choose one of the upper four register pairs

      Rd = (Rd * 2 )+24;

      //Temporary varoables for performing the operation

      short temp0 = 0;

      short temp1 = 0;

      int result = 0;

 

      //Add the immediate to the register pair

      temp0 = (short)(((short)regFile[Rd])&0x00ff);

      temp1 = (short)((((short)regFile[Rd+1])&0x00ff) << 8);

      result = (int) ((temp0|temp1) + K);

      regFile[Rd] = (byte) (result & 0x000000ff);

      regFile[Rd+1] = (byte) ((result &0x0000ff00) >>> 8);

 

      //Update SREG

 

      regFileIO[0x3f]=setBit(regFileIO[0x3f],3,(!getBit(regFile[Rd+1],7)) & getBit (result,15));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(result,15));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],1,(result == 0));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],0,!getBit(result,15) & getBit(temp1,15));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],4,getBit(regFileIO[0x3f],2) ^ getBit(regFileIO[0x3f],3));

      //Advance clock by time period since

      //this is a 2-cycle instruction

      cycleNum ++;

 

      //Increment program counter

      PC++;

 

    }

 

     //ASR

    if((instr & 0x0e0f) == 0x0405){

    //System.out.println("ASR");

      //Get the result of the shift operation

      R = (byte)(((int)regFile[Rd] << 24)>> 25);

      //Update SREG

 

      regFileIO[0x3f]=setBit(regFileIO[0x3f],2,getBit(R,7));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],1, R == 0);

      regFileIO[0x3f]=setBit(regFileIO[0x3f],0,getBit(regFile[Rd],0));

      regFileIO[0x3f]=setBit(regFileIO[0x3f],3,getBit(regFileIO[0x3f],2) ^ getBit(regFileIO[0x3f], 0));