/*
   Copyright (C) 1999 T. Scott Dattalo

This file is part of gpsim.

gpsim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

gpsim is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with gpsim; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


#include <iostream>
#include <iomanip>
#include <string>
#include <stdio.h>
#include <vector>

#include "command.h"
#include "cmd_dump.h"
#include "input.h"

#include "../src/pic-processor.h"
#include "../src/14bit-processors.h"
#include "../src/interface.h"
#include "../src/eeprom.h"

cmd_dump dump;

static cmd_options cmd_dump_options[] =
{
  {"e", cmd_dump::DUMP_EEPROM,    OPT_TT_BITFLAG},
  {"r", cmd_dump::DUMP_RAM,       OPT_TT_BITFLAG},
  {"s", cmd_dump::DUMP_SFRS,      OPT_TT_BITFLAG},
  {0,0,0}
};


cmd_dump::cmd_dump(void)
{ 
  name = "dump";
  abbreviation = "du";

  brief_doc = string("Display either the RAM or EEPROM");

  long_doc = string ("dump [r | e | s]\n"
    "\tdump r or dump with no options will display all of the file\n"
    "\t       registers and special function registers.\n"
    "\tdump e will display the contents of the eeprom (if the pic\n"
    "\t       being simulated contains any)\n"
    "\tdump s will display only the special function registers.\n");

  op = cmd_dump_options; 
}



#define REGISTERS_PER_ROW  16
#define SFR_COLUMNS         3
#define MAX_SFR_NAME       10

void cmd_dump::dump_sfrs(void)
{
  Processor * cpu = GetActiveCPU();
  unsigned int reg_size = cpu->register_size();
  unsigned int uToDisplayCount = 0;
  unsigned int uColumns = SFR_COLUMNS;
  vector<Register*> RegListToDisplay;
  unsigned int auTopRowIndex[SFR_COLUMNS];
  // Examine all registers this pic has to offer
  list <ProgramMemoryAccess *> :: iterator itPMA;

  itPMA = cpu->pma_context.begin();
  for(; itPMA != cpu->pma_context.end(); itPMA++) {
    list<Register *>::iterator itReg;
    for(itReg = (*itPMA)->SpecialRegisters.begin();
        itReg != (*itPMA)->SpecialRegisters.end();
        itReg++) {
      uToDisplayCount++;
      RegListToDisplay.push_back(*itReg);
    }
  }
  if(RegListToDisplay.size() == 0) {
    for (unsigned int i = 0; i < cpu->register_memory_size(); i++) {
      Register * pReg = cpu->registers[i];
      if(pReg->isa() == Register::SFR_REGISTER &&
        // Found an sfr. Display its contents only if not aliased
        // at some other address too.
        i == pReg->address) {
        uToDisplayCount++;
        RegListToDisplay.push_back(pReg);
      }
    }
  }
  //
  //  All this is so we can have the reg number sequence go
  //  from top to bottom of each column instead of across columns.
  unsigned int uMod = uToDisplayCount % uColumns;
  unsigned int uRowsPerColumn = uToDisplayCount / uColumns;
  auTopRowIndex[0] = 0;
  for (unsigned int i = 1; i < sizeof(auTopRowIndex) / sizeof(unsigned int);
    i++) {
    auTopRowIndex[i] = auTopRowIndex[i-1] + uRowsPerColumn + (uMod > i ? 1 : 0);
  }
  uRowsPerColumn += (uMod == 0 ? 0 : 1);

  putchar('\n');
  unsigned int uRegCount = 0;
  for (unsigned int uRow = 0; uRow < uRowsPerColumn; uRow++) {
    for (unsigned int uColCurrent = 0; uColCurrent < uColumns; uColCurrent++) {
      unsigned int uIndex = auTopRowIndex[uColCurrent] + uRow;
      if(uRegCount > uToDisplayCount)
        break;
//      printf("%03d ", uIndex); // used for testings
      uRegCount++;
      Register *pReg = RegListToDisplay[uIndex];
      printf("%03x %-7s = %0*x   ", pReg->address,
        pReg->name().c_str(), reg_size * 2,
        pReg->get_value());
    }
    putchar('\n');
  }
}

void cmd_dump::dump(int mem_type)
{
  unsigned int i, j, reg_num,mem_size=0,reg_size=1,uRegPerRow = REGISTERS_PER_ROW;
  unsigned int v;
  bool 
    previous_row_is_invalid=false, 
    all_invalid=false;

  Register **fr=0;

  if(!have_cpu(1))
    return;

  switch(mem_type)
    {
    case DUMP_EEPROM:
      {
      pic_processor *pic = dynamic_cast<pic_processor *> (GetActiveCPU());
      if(pic && pic->eeprom) {
        fr = pic->eeprom->get_rom();
        mem_size = pic->eeprom->get_rom_size();
      } else
        return;
      }
      break;
    case DUMP_RAM:
      mem_size = GetActiveCPU()->register_memory_size();
      reg_size = GetActiveCPU()->register_size();
      uRegPerRow = reg_size == 1 ? REGISTERS_PER_ROW : 8;
      fr = GetActiveCPU()->registers;
      break;
    case DUMP_SFRS:
      dump_sfrs();
      putchar('\n');
      return;
    }

  if(mem_size == 0)
    return;

  gpsim_set_bulk_mode(1);
  

  if(reg_size == 1) {
    printf("     ");
    // Column labels
    for (i = 0; i < uRegPerRow; i++)
      printf(" %0*x", reg_size * 2, i);

    putchar('\n');
  }
  reg_num = 0;
  for (i = 0; i < mem_size; i+=uRegPerRow) {

    /* First, see if there are any valid registers on this row */
    all_invalid = true;
    for (j = 0; j < uRegPerRow; j++) {
      if(fr[i+j]->address) {
        all_invalid = false;
        break;
      }
    }
    if(!all_invalid) {
      previous_row_is_invalid = false;
    
      printf("%03x:  ",i);

      for (j = 0; j < uRegPerRow; j++)
      {
        reg_num = i  + j;

        if( (reg_num < mem_size) && ( reg_num || fr[reg_num]->address)) {

          v = fr[reg_num]->get_value();
          printf("%0*x ",reg_size * 2, v);
        } else {
          for (unsigned int i = 0; i < reg_size; i++)
            printf("--");
          putchar(' ');
        }
      }
      if(reg_size == 1) {
        // don't bother with ASCII for > 8 bit registers
        printf("   ");

        for (j = 0; j < uRegPerRow; j++)
        {
          reg_num = i + j;
          v = fr[reg_num]->get_value();
          if( (v >= ' ') && (v <= 'z'))
            putchar(v);
          else
            putchar('.');
        }
      }
      putchar('\n');
    } else {
      if(!previous_row_is_invalid)
        putchar('\n');
      previous_row_is_invalid = true;
      reg_num += REGISTERS_PER_ROW;
    }
  }

  // Now Dump the sfr's 

  if(mem_type == 2) {

    dump_sfrs();

    pic_processor *pic = dynamic_cast<pic_processor *>(GetActiveCPU());
    if(pic)
      printf("\n%s = %02x\n",pic->W->name().c_str(), pic->W->get_value());

    printf("pc = 0x%x\n",GetActiveCPU()->pc->value);
  }
  
  gpsim_set_bulk_mode(0);

}


syntax highlighted by Code2HTML, v. 0.9.1