avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] simulator


From: ChristoGeo
Subject: Re: [avr-gcc-list] simulator
Date: Mon, 01 Oct 2001 15:29:11 -0700

Hi list, basically, I code 8051/6805 as microcode and let the C compiler (BC 3.1) sort it out. The compiler will take my switch() and make a nice jump table out of the opcodes.

below is some of a simulator I use for a Custom 8051. It gives you the general idea. Keep in mind, I update my display after every opcode is executed. I am going to change my ways though and make a mapping of where registers live on my drawn screen to only updated 1 register (since most instructions update 1-2 values max).

My simulator differs from a real cpu core from the fact that I automatically add the PC with a fixed opcode length from a table. In real life, the PC is like your X,Y, or Z pointers and is incremented by fetches or writes to change the contents (I also specialize in real-time AVR based simulation of 8051 and 6805 ;) ).

I really prefer writing embedded simulators. The AVR is perfect! I use external SRAM to store my entire code in place. I download new code or read out code by routines inside the AVR. My average AVR 6805 opcode is under 10 clks!!!

take care,
Chris


(code is below)


At 01:54 PM 10/1/2001 -0600, Theodore A. Roth wrote:
Chris,

I'd be interested in seeing some of your code for other cpu cores. I'm
curious how you map the opcodes into function calls and such. I'd like to
get some more ideas in mind head before digging into C code.

It looks like python is _too_ slow. At least the python stuff got me a
prototype to work from (if the design isn't completely stupid) and a good
deal of knowledge about the avr core.

Ted Roth

On Mon, 1 Oct 2001, ChristoGeo wrote:

:)I don't say too much here but I would suggest that any simulator out there
:)be written in C not Python.  Only thing worse would be TCL based.
:)
:)I could write the opcodes in C for you if you desire.  I write cpu cores
:)all the time in C for pleasure
:)
:)Regards,
:)Chris
:)
:)
:)
:)At 06:49 AM 10/1/2001 +0000, address@hidden wrote:
:)
:)
:)
:)>Sounds interesting :-)
:)>Too bad I'm not familiar with Python, but I've been
:)>"fooling around" with AVR:s for some time ...
:)>And There's not too many (1--) AVR simulators for Linux ...
:)>Sounds like a good enough reason to pick up Python ...
:)>
:)>Have You got a web-page, or how do You plan to make
:)>the code available ??
:)>
:)>BR : Johan
:)>
:)>BTW : Is 'pyhton' a typo, or am I completely lost ??
:)>
:)>"Theodore A. Roth" <address@hidden> wrote:
:)>
:)> > Hi,
:)> >
:)> > I've been working on a simluator written in pyhton for the last couple of
:)> > weeks. It's not near done yet, but I can already run programs that don't
:)> > use the IO registers. Right now I'm working on hooks for the virtual
:)> > connections to the IO pins of devices.
:)> >
:)> > I'm not sure if it could be accessed from gdb, but it has been in the back
:)> > of my mind. Right now I'm only using assembly code to test it so as to
:)> > keep the programs simple and be able to understand what's going on.
:)> >
:)> > So far, I've got the basics for the at90s1200, 4414 and 8515 going, but
:)> > I've only been testing with the 8515. It should be easy to add new
:)>devices
:)> > in the feature, since I've been designing it with that in mind.
:)> >
:)> > If anyone's interested, I'd be more than happy to make the code
:)>available.
:)> >
:)> > Ted Roth
:)> > address@hidden


// Bits used in SimStat
//
#define _console        0x01    // bit 0
#define _debug          0x02    // bit 1

// Program Status Word Bits
//
#define CY      0x80
#define AC      0x40
#define F0      0x20
#define RS1     0x10
#define RS0     0x08
#define OV      0x04
#define USER    0x02
#define P       0x01

        // 0000-7FFF: ROM
        // 8000-DFFF: EEPROM


 uchar  SimStat,        // bit 1=debug bit 0=console
        SaveStat,       // Save of SimStats for interrupts
        //
        SFR[0xFF],
        RAM[0xFF],
        //
        *R0,*R1,*R2,*R3,
        *R4,*R5,*R6,*R7,
        //
        *SP     = &SFR[0x81],
        *DPL    = &SFR[0x82],
        *DPH    = &SFR[0x83],
        //
        *P1     = &SFR[0x90],   // P1
        *DDR1   = &SFR[0x94],   // P1 DDR
        //
        *XDPH   = &SFR[0xB3],   // Hi-MovX
        *PSW    = &SFR[0xD0],   // CY  AC  F0 RS1 RS0  OV  -  P
        *AReg   = &SFR[0xE0],
        *BReg   = &SFR[0xF0];


uint    PC      = 0x0000,       // Program Counter Start Ofs
        *DPTR   = &SFR[0x82],   // 2 bytes wide dpl|dph)
        Map;                    // result of bitmap call

ulong   CYCLES= 0L;

int     oc1,            // Current OpCode fetched by PC
        oc2,            // operand 1
        oc3;            // operand 2

 FILE   *log;           // output of core into text file


        // =-=-=-=-=-=-=-=-=-=-= //
        // Sim Support Functions //
        // =-=-=-=-=-=-=-=-=-=-= //

// Our Interrupts for system (turn off console updates, debug mode, fake send/recv, etc)
        //
void    Interrupts()
{
 uint   i;

 switch(PC)
  {

// case 0x3AE7: SimStat |= _debug; // disassemble 5 lines from PC and pause on each opcode.. (step through)
//   case 0x2fdd:
//              Pause();
//              break;


   case 0x3132: // Algorithm #1 entry point
   case 0x3155: // Algorithm #2 entry point
   case 0x5532: // ram tests
   case 0x4555: // clear ram
   case 0x2214: // Calc Checksum
                SaveStat = SimStat;
                SimStat = 0;    // no console, no debug
                break;



   case 0x3333: // Algorithm #1 exit point
   case 0x256E: // ram tests are finished..
   case 0x333A: // clear ram
   case 0x2222: // Calc Checksum exit

                SimStat = SaveStat;     // restore sim_state bits
                break;


   case 0x1239: // CMS Sendbyte
                SendByte(*AReg);
                oc1 = 0x22;     // implant a ret now!
                Pause();
                break;

                // eewrite @dptr from @r0 4 bytes
                //
   case 0x00BE: gotoxy(1,24);
                cprintf("eeburn %04X: %02X %02X %02X %02X",(*DPTR),
                        RAM[(*R0)],
                        RAM[(*R0)+1],
                        RAM[(*R0)+2],
                        RAM[*(R0)+3]);

                for (i=0; i<4; i++)
                 Core[(*DPTR)++] = RAM[(*R0)++];

                (*AReg)=0;
                oc1 = 0x22;
                Pause();
                break;

  } // end of switch
}



uint    BitMap(uchar Bit)
{
 uchar  a,
        Masks[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

        a = (Bit>0x7F) ? (Bit&0xF8) : ((Bit/8)+0x20);
        return ((uint)(a<<8) | Masks[(Bit%8)] ); // compress return
}

// this is a function on purpose because some of the controllers I work with can do wacky things I cant explain here!
        //
void    AdjPC(uchar arg1)
{
 PC += arg1;
}


        // wait for a keypress but let the main key-catcher
        // process the keystroke.
        //
void    Pause(void)
{
 while (!kbhit())
  ;
}


void InitRegs(void)
{
  uint  i;

  for (i=0; i<0x100; i++)
   RAM[i] = 0;

  memset(SFR,0x00,0xFF);        // clear all sfr space

  PC    = 0x0000;
  *DPTR = 0x0000;               // DPTR = 0000
  *SP   = 0x07;                 // SP = 07h

  *P1   = 0x01;
  PackPtr =0;                   // for faking recvbyte..
}


        // Dumps an array (eeprom,ram,sfr,xram...) to a file..
        //
void    StoreRegs(uchar *Filename, uchar *Array, uint Length)
{
 FILE   *out;
 uint   i;

 if ((out = fopen(Filename, "wb"))== NULL)
  {
   fprintf(stderr, "Cannot open input file.\n");
   exit(1);
  }

 for (i=0; i<Length; i++)
  fputc(Array[i], out);
 fclose(out);
}



        // oc1 = arg1
        // oc2 = arg2
        //
        // PC = ( ((PC+2)&0xF800) | (((oc1&0xE0)<<3) | oc2) );
        //
void    ajmp(uchar arg1, uchar arg2)
{
  PC &= 0xF800;
  PC |= ( ((arg1&0xE0)<<3) | arg2);
}


void    add(uchar arg1)
{

 if  ( ((uint)(*AReg + arg1)) > 0xFF)
  (*PSW) |= CY;    // Set Carry
 else
  (*PSW) &= ~CY;   // Clear Carry

 (*AReg) += arg1;
}


void    addc(uchar arg1)
{
 if ((*PSW)&CY)
  arg1++;       // add +1

 if ( ((uint)(*AReg)+arg1) > 0xFF)
  (*PSW) |= CY;  // Set Carry
 else
  (*PSW) &= ~CY; // Clear Carry

 (*AReg) += arg1;
}


void    subb(uchar arg1)
{
 if ((*PSW)&CY)
  arg1++;       // subtract one more

 if (((uint)(*AReg)-arg1) > 0xFF)
  *PSW |= CY;  // Set Carry
 else
  *PSW &= ~CY; // Clear Carry
 (*AReg) -= arg1;
}


void    cjne(uchar arg1, int arg2, int relofs)
{
 if (relofs > 0x7F)
  relofs |= 0xFF00;

 if (arg1 < arg2)
  (*PSW) |= CY;  // Set Carry
 else
  (*PSW) &= ~CY; // Clr Carry

 if (arg1 != arg2)
  PC += relofs;
}


void    djnz(uchar *arg1, uint relofs)
{
 if (relofs > 0x7F)
  relofs |= 0xFF00;

 (*arg1)--;

 if (*arg1 !=0)
  PC += relofs;
}


void    push(uchar arg1)
{
 (*SP)++;
 RAM[(*SP)] = arg1;
}

uchar   pop()
{
 uchar  a;

 a = RAM[*SP];     // Pop High Address
 (*SP)--;
 return(a);
}


void main(int argc, char **argv)
{
 uint   Address,        // Given address for ease of use..
        i=0,
        X=0;

 uchar  a,              // GP Working Register
        ch,             // GP for Key Entry
        *iptr,
        *jptr,          // i+j GP Pointers for 85 Opcode
        AdjBYTE=0,
        AdjBIT=0,
        c,xx=0,yy=0;

// directvideo=1;
 clrscr();

 InitRegs();             // Init Regs to power up values..
// LoadHex("alarm.hex"); // Load Intel-Hex file into core[]
// LoadEEProm(argv[1]);    // Load in .BIN of EEProm of choice..

 SimStat |= _console;// + _debug;       // enable console display

 if ((log = fopen("CORE.LOG", "wt"))== NULL)
  {
   fprintf(stderr, "Cannot open log file.\n");
   exit(1);
  }

 while (ch !=27)
 {

 R0 = &RAM[(*PSW)&0x18];
 R1 = &RAM[((*PSW)&0x18)+1];
 R2 = &RAM[((*PSW)&0x18)+2];
 R3 = &RAM[((*PSW)&0x18)+3];
 R4 = &RAM[((*PSW)&0x18)+4];
 R5 = &RAM[((*PSW)&0x18)+5];
 R6 = &RAM[((*PSW)&0x18)+6];
 R7 = &RAM[((*PSW)&0x18)+7];

        // if the display is on, show the current values after each opcode
        //
  if (SimStat & _console)
   {
    gotoxy(1,1);
                 // Internal Ram
                 //

                 for (i=0x00; i<0x100; i+=16)
cprintf("%02X: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n\r",
                         (i&0xF0),
                         
RAM[i],RAM[i+1],RAM[i+2],RAM[i+3],RAM[i+4],RAM[i+5],RAM[i+6],RAM[i+7],
                         
RAM[i+8],RAM[i+9],RAM[i+10],RAM[i+11],RAM[i+12],RAM[i+13],RAM[i+14],RAM[i+15]);

    gotoxy(55,1); cprintf("PC:   %04X  DPTR: %04X", PC, *DPTR);
    gotoxy(55,2); cprintf("X-R0: %04X  X-R1: %04X",
                        ((*XDPH)<<8)|(*R0),((*XDPH)<<8)|(*R1));
    gotoxy(55,3); cprintf("SP:   %02X    CLK:  %08lu", *SP,CYCLES);
    gotoxy(55,4); cprintf("A:    %02X    B:    %02X",*AReg,*BReg);
    //
gotoxy(55,6); cprintf("R0: %02X RSEL: %01i", *R0, ((((*PSW)&RS0)|((*PSW)&RS1))>>3));
    gotoxy(55,7); cprintf("R1:   %02X    CY:   %01i", *R1, ((*PSW)&CY)>>7);
    gotoxy(55,8); cprintf("R2:   %02X    Z:    %01i", *R2, ((*AReg)==0x00));
    gotoxy(55,9); cprintf("R3:   %02X    F0:   %01i", *R3, ((*PSW)&F0)>>5);
    gotoxy(55,10);cprintf("R4:   %02X", *R4);
    gotoxy(55,11);cprintf("R5:   %02X    SS:   %02X", *R5, SimStat);
    gotoxy(55,12);cprintf("R6:   %02X", *R6);
    gotoxy(55,13);cprintf("R7:   %02X", *R7);

//    SimStat &= ~_console;     // turn off console now
   }

 if (SimStat & _debug)
  {
   c=0;
   gotoxy(1,17); c= DisAsm(PC,1);       // 1 = show in red..
   gotoxy(1,18); c+=DisAsm(PC+c,0);
   gotoxy(1,19); c+=DisAsm(PC+c,0);
   gotoxy(1,20); c+=DisAsm(PC+c,0);
   gotoxy(1,21); c+=DisAsm(PC+c,0);

  Pause();
  }

  if (kbhit())
   {
    ch=getch();
    switch(toupper(ch))
     {
        // Flip console on/off
        //
      case 'C': SimStat ^= _console;
                break;

        // Flip debug on/off!
        //
      case 'D': SimStat ^= _debug;
                break;

                // Save eeprom area..
                //
      case 'S': StoreRegs("CORE.BIN", Core,0x9000);
                StoreRegs("EEPROM.BIN", &Core[0x8000], 0x1000);
                StoreRegs("RAM.BIN", RAM, 0x100);
                StoreRegs("SFR.BIN", &SFR[0x80], 0x80);
                break;

     } // end of switch(toupper(ch))
   } //end of if kbhit()

   oc1 = Core[PC];
   oc2 = Core[PC+1];
   oc3 = Core[PC+2];

   Interrupts();                // do interrupts before PC is incremented!
   PC += OpTable[oc1].length;

   switch(oc1)
   {
                // NOP
                //
    case 0x00:  break;


    case 0x01:  // AJMP xx
    case 0x21:
    case 0x41:
    case 0x61:
    case 0x81:
    case 0xA1:
    case 0xC1:
    case 0xE1:  ajmp(oc1,oc2);
                break;


                // LJMP 16 Bit Ofs
                //
    case 0x02:  PC = (oc2<<8) | oc3;
                break;


                // RR   A
                //
    case 0x03:  (*AReg) = (((*AReg) >> 1) | ((*AReg) << 7));
                break;


                // INC  A
                //
    case 0x04:  (*AReg)++;
                break;

                // INC  XX
                //
    case 0x05:  if (oc2 > 0x7F) SFR[oc2]++;
                 else RAM[oc2]++;
                break;

    case 0x06:  RAM[(*R0)]++; break;          // inc @r0
    case 0x07:  RAM[(*R1)]++; break;          // inc @r1
    case 0x08:  (*R0)++; break;               // inc r0
    case 0x09:  (*R1)++; break;               // inc r1
    case 0x0A:  (*R2)++; break;               // inc r2
    case 0x0B:  (*R3)++; break;               // inc r3
    case 0x0C:  (*R4)++; break;               // inc r4
    case 0x0D:  (*R5)++; break;               // inc r5
    case 0x0E:  (*R6)++; break;               // inc r6
    case 0x0F:  (*R7)++; break;               // inc r7


                // JBC  XX, XX
                //  10 F7 FD - jbc b.7, $
                // sfr's bitmap out exactly,
                //
    case 0x10:  if (oc3 > 0x7F)
                 oc3 |= 0xFF00;

                Map=BitMap(oc2);

                if ((Map>>8) < 0x80)
                 {
                  if (RAM[(Map>>8)]&(Map&0xFF))
                   PC += oc3;
                  RAM[(Map>>8)] &= ~(Map&0xFF);
                 }
                else
                 {
                  if (SFR[(Map>>8)]&(Map&0xFF))
                   PC += oc3;
                  SFR[(Map>>8)] &= ~(Map&0xFF);
                 }
                break;


    case 0x11:  // ACALL xx
    case 0x31:
    case 0x51:
    case 0x71:
    case 0x91:
    case 0xB1:
    case 0xD1:
    case 0xF1:  push((uchar)PC&0xFF);
                push((uchar)(PC>>8));
                ajmp(oc1,oc2);
                break;


                // LCALL XX XX
                //
    case 0x12:  push((uchar)PC&0xFF);
                push((uchar)(PC>>8));
                PC = (oc2<<8) | oc3;
                break;


                // RRC  A
                //
    case 0x13:  if ((*PSW)&CY)
                 {              // Carry is set prior to shift
                   if ((*AReg)&1)
                    (*PSW) |= CY;       // Set Carry
                   else
                    (*PSW) &= ~CY;      // Clear Carry

                   (*AReg) >>=1;
                   (*AReg) |=0x80;      // Move in CY
                 }
                else
                 {              // Carry is clr prior to shift
                   if ((*AReg)&1)
                    (*PSW) |= CY;       // Set Carry
                   else
                    (*PSW) &= ~CY;      // Clear Carry
                    (*AReg) >>=1;
                    (*AReg) &= 0x7F;    // Added 17 July 1998
                 }
                break;


                // DEC  A
                //
    case 0x14:  (*AReg)--;
                break;


                // DEC XX
                //
    case 0x15:  if (oc2 > 0x7F) SFR[oc2]--;
                 else RAM[oc2]--;
                break;

    case 0x16:  RAM[(*R0)]--; break;          // dec @r0
    case 0x17:  RAM[(*R1)]--; break;          // dec @r1
    case 0x18:  (*R0)--; break;               // dec r0
    case 0x19:  (*R1)--; break;               // dec r1
    case 0x1A:  (*R2)--; break;               // dec r2
    case 0x1B:  (*R3)--; break;               // dec r3
    case 0x1C:  (*R4)--; break;               // dec r4
    case 0x1D:  (*R5)--; break;               // dec r5
    case 0x1E:  (*R6)--; break;               // dec r6
    case 0x1F:  (*R7)--; break;               // dec r7


    .....snip.....

    case 0x26:  add(RAM[(*R0)]); break;       // add a, @r0
    case 0x27:  add(RAM[(*R1)]); break;       // add a, @r1
    case 0x28:  add(*R0); break;              // add a, r0
    case 0x29:  add(*R1); break;              // add a, r1
    case 0x2A:  add(*R2); break;              // add a, r2
    case 0x2B:  add(*R3); break;              // add a, r3
    case 0x2C:  add(*R4); break;              // add a, r4
    case 0x2D:  add(*R5); break;              // add a, r5
    case 0x2E:  add(*R6); break;              // add a, r6
    case 0x2F:  add(*R7); break;              // add a, r7


    ....snip....

    case 0xF6:  RAM[(*R0)] = (*AReg); break;  // mov @r0, a
    case 0xF7:  RAM[(*R1)] = (*AReg); break;  // mov @r1, a
    case 0xF8:  (*R0) = (*AReg); break;       // mov r0, a
    case 0xF9:  (*R1) = (*AReg); break;       // mov r1, a
    case 0xFA:  (*R2) = (*AReg); break;       // mov r2, a
    case 0xFB:  (*R3) = (*AReg); break;       // mov r3, a
    case 0xFC:  (*R4) = (*AReg); break;       // mov r4, a
    case 0xFD:  (*R5) = (*AReg); break;       // mov r5, a
    case 0xFE:  (*R6) = (*AReg); break;       // mov r6, a
    case 0xFF:  (*R7) = (*AReg); break;       // mov r7, a

   } // End of switch

  CYCLES += OpTable[oc1].cycles;
 } //end of while(ch!=27)
 fclose(log);
}






reply via email to

[Prev in Thread] Current Thread [Next in Thread]