/*

Freely Distributable C30 Simulator Package

Copyright (c) 1996-1998 The University of Texas
All Rights Reserved.

This program 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 of the License, or
(at your option) any later version.
 
This program 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.
 
The GNU Public License is available in the file LICENSE, or you
can write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA, or you can find it on the
World Wide Web at http://www.fsf.org.

Authors: Chi Duong, Brian Evans and Chris Moy 
Version: @(#)memmap.cc	1.26	01/19/98

Department of Electrical and Computer Engineering
The University of Texas, Austin, TX 78712-1084

*/

/*
The following memory map information is taken from the
C30 User's Guide.

1. Portion of the C30 Memory Map accessible by Users

 4 kwords of ROM   0x000000C0 - 0x00000FFF
 8 kwords reserved 0x00802000 - 0x00803FFF
 8 kwords reserved 0x00806000 - 0x00807FFF
 1 kword in RAM0   0x00809800 - 0x00809BFF
 1 kword in RAM1   0x00809C00 - 0x00809FFF
 Total: 22 kwords

2. Portion of the C31 Memory Map Accessible by Users

 32 kwords reserved 0x00800000 - 0x00807FFF
  1 kword in RAM0   0x00809800 - 0x00809BFF
  1 kword in RAM1   0x00809C00 - 0x00809FFF  
 Total: 34 kwords 

3. Portion of the C32 Memory Map Accessible by Users

  32kwords reserved    0x00800000 - 0x00807FFF
  26kwords reserved    0x00809800 - 0x0080FFFF
  319.5kworks reserved 0x00830000 - 0x0087FDFF
  256words of RAM0     0x0087FE00 - 0x0087FEFF
  256words of RAM1     0x0087FF00 - 0x0087FFFF
 Total: 58.5 kwords + 319.5 kwords

		C30		C31		C32
------------------------------------------------------------
*Boot loader	No		Yes		Yes
*ROM		4k(C0h-FFFh)	no 		no
*on-chip RAMs	2k		2k		512
(RAM block 0	(809800h-	(809800h-	(87FE00h-
 and block 1)	 809FFFh)	 809FFFh)	 87FFFFh)

Basically, all C3x have the same memory space (0-FFFFFFh).  However, C32
has more memory on Reserved (58k words vs 16k words on C30)  and on
External Memory (IOSTRB)' Active (128k words vs 8k words of Expansion Bus
(IOSTRB)' Active on C30).
*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "state.h"
#include "pipeline.h"
#include "memmap.h"


/*
Input a long c3x memory address and returns a pointer to the corresponding
location in simulated memory.  The routine compares the address to the
appropriate c3x memory map, and then calculates the corresponding pointer
in local memory.
*/
uint32* C30SimMemMap(state *st, uint32 addr) {
  uint32* ret = 0;

  switch (st->c30proc) {
    case __c3x:
    case __c30:
      /* 4 kwords ROM, 1 kword RAM0, 1 kword RAM1, 16 kwords reserved */
      if ((addr & 0xFFFFFC00L) == 0x00809C00L)
        ret = (st->ram1 + (addr - 0x00809C00L));
      else if ((addr & 0xFFFFFC00L) == 0x00809800L)
        ret = (st->ram0 + (addr - 0x00809800L));
      else if ((addr & 0xFFFFE000L) == 0x00806000L)
        ret = (st->reserved1 + (addr - 0x00806000L));
      else if ((addr & 0xFFFFE000L) == 0x00802000L)
        ret = (st->reserved0 + (addr - 0x00802000));
      else if ((addr >= 0x000000C0L) && (addr <= 0x00000FFFL))
        ret = (st->rom + (addr - 0x000000C0L));
      else 
        ret = &st->dummy;  /* a somewhat safe mem location */
      break;

    case __c31:
      /* 1 kword RAM0, 1 kword RAM1, 32 kwords reserved */
      if ((addr & 0xFFFFFC00L) == 0x00809C00L)
        ret = (st->ram1 + (addr - 0x00809C00L));
      else if ((addr & 0xFFFFFC00L) == 0x00809800L)
        ret = (st->ram0 + (addr - 0x00809800L));
      else if ((addr & 0xFFFF8000L) == 0x00800000L)
        ret = (st->reserved0 + (addr - 0x00800000L));
      else 
        ret = &st->dummy;  /* a somewhat safe mem location */
      break;

    case __c32:
      /* 0.25 kword RAM0, 0.25 kword RAM1, 58 kwords reserved */
      if ((addr & 0xFFFFFF00L) == 0x0087FF00L)
        ret = (st->ram1 + (addr - 0x0087FF00L));
      else if ((addr & 0xFFFFFF00L) == 0x0087FE00L)
        ret = (st->ram0 + (addr - 0x0087FE00L));
      else if ((addr >= 0x00809800L) && (addr <= 0x0080FFFF))
        ret = (st->reserved1 + (addr - 0x00809800L));
      else if ((addr & 0xFFFF8000L) == 0x00800000L)
        ret = (st->reserved0 + (addr - 0x00800000L));
      else 
        ret = &st->dummy;  /* a somewhat safe mem location */
      break;
  }
  return ret;
}

/*
Allocate the proper amount of memory in the processor state 
data structure for the given C30 processor type.  This function
returns the amount of memory allocate in C30 words, so that
0 indicates an error.
*/
uint32 C30SimInitMemoryMap(state *st, c30ProcType c30member) {
  uint32 totalC30words = 0;
  st->c30proc = c30member;

  /* We'll be using a lot of pointer arithmetic which automatically */
  /* adjusts pointer addition according to the size of data type */ 
  switch (c30member) {
    case __c3x:
    case __c30:
      totalC30words = 22*1024;
      st->addrSpace = (c30mem*) malloc(totalC30words * sizeof(c30mem));
      st->rom = st->addrSpace;
      st->reserved0 = st->rom + 4*1024;
      st->reserved1 = st->reserved0 + 8*1024;
      st->ram0 = st->reserved1 + 8*1024;
      st->ram1 = st->ram0 + 1024;
      st->romEnd = st->reserved0;
      st->ram0End = st->ram1;
      st->ram1End = st->ram1 + 1024;
      break;

    case __c31:
      totalC30words = 34*1024;
      st->addrSpace = (c30mem*) malloc(totalC30words * sizeof(c30mem));
      st->rom = 0;                        /* No ROM */
      st->reserved0 = st->addrSpace;      /* There is only one reserved bank */
      st->reserved1 = st->reserved0;
      st->ram0 = st->reserved0 + 32*1024;
      st->ram1 = st->ram0 + 1024;
      st->romEnd = 0;
      st->ram0End = st->ram1;
      st->ram1End = st->ram1 + 1024;
      break;

    case __c32:
      totalC30words = 59*1024;
      st->addrSpace = (c30mem*) malloc(totalC30words * sizeof(c30mem));
      st->rom = 0;                        /* No ROM */
      st->reserved0 = st->addrSpace;
      st->reserved1 = st->reserved0 + 32*1024;
      st->ram0 = st->reserved1 + 26*1024;
      st->ram1 = st->ram0 + 256;
      st->romEnd = 0;
      st->ram0End = st->ram1;
      st->ram1End = st->ram1 + 256;
      break;
  }

  /* Initialize the C30 memory to zero */
  memset(st->addrSpace, 0, totalC30words*sizeof(c30mem));

  return totalC30words;
}

/*
Deallocate dynamic memory allocated for the C30 address space.
*/
int C30SimFreeMemoryMap(state *st) {
  if (st->addrSpace) free(st->addrSpace);
  st->addrSpace = 0;
  st->rom = 0;
  st->reserved0 = 0;
  st->reserved1 = 0;
  st->ram0 = 0;
  st->ram1 = 0;
  st->romEnd = 0;
  st->ram0End = 0;
  st->ram1End = 0;
  return 1;
}

/*
access counts the number of times a memory block has been accessed
in a cycle and stores the result in the pipeline struct
*/
int C30SimMemAccess(uint32* pt, state *st, pipeline *pipe) {
  if (((uint32)pt >= (uint32)st->rom) && ((uint32)pt < (uint32)st->romEnd)) {
    if (++pipe->accessROM == 3) {
        pipe->interlock = 1;
        st->DSKdebStep = 1;
        return 2;
    }
  }
  else if (((uint32)pt >= (uint32)st->ram0) && ((uint32)pt < (uint32)st->ram0End)) {
    if (++pipe->access0 == 3) {
        pipe->interlock = 1;
        st->DSKdebStep = 1;
        return 2;
    }
  }
  else if (((uint32)pt >= (uint32)st->ram1) && ((uint32)pt < (uint32)st->ram1End)) {
     if (++pipe->access1 == 3)  {
        pipe->interlock = 1;
        st->DSKdebStep = 1;
        return 2;
     }
  }

  return 0;
}

void C30SimRegAccess(uint32* pt, state *st, pipeline *pipe) {
  if ((pt >= &st->ar0) && (pt <= &st->bk))
    pipe->accessAR = pipe->tempAccessAR = 0;
  else if (pt == &st->dp)
    pipe->accessDP = pipe->tempAccessDP = 0;
  else if (pt == &st->sp)
    pipe->accessSP = pipe->tempAccessSP = 0;
}

/*
Take a register or memory location as input (character string)
and return a pointer to the requested location
*/
uint32* C30SimGetLoc(const char *input, state *st) {
  uint32* ret = 0;
  char firstChar, secondChar, thirdChar;

  /* return if the string 'input' is empty */
  if ( input == 0 || *input == 0 ) return 0;

  /* check to see if 'input' is an address in c30 memory */
  firstChar = *input;
  if ( isdigit(firstChar) ) {
    uint32 mem;
    if ( sscanf(input, C30_MEMORY_SCANF, &mem) == 1 )
      return C30SimMemMap(st, mem);
    else
      return 0;
  }

  /* return if the string 'input' is only one character in length */
  if ( *++input == 0 ) return 0;
  secondChar = *input++;

  /* match register location */
  firstChar = tolower(firstChar);
  secondChar = tolower(secondChar);
  thirdChar = tolower(*input);

  /* unravel the string matching into matching characters for speed */
  switch (firstChar) {

    case 'a':                         /* match Sregs[__ar0] - Sregs[__ar7] */
      if (secondChar == 'r') {
        switch (thirdChar) {
          case '0':
            ret = &st->ar0;
            break;
          case '1':
            ret = &st->ar1;
            break;
          case '2':
            ret = &st->ar2;
            break;
          case '3':
            ret = &st->ar3;
            break;
          case '4':
            ret = &st->ar4;
            break;
          case '5':
            ret = &st->ar5;
            break;
          case '6':
            ret = &st->ar6;
            break;
          case '7':
            ret = &st->ar7;
            break;
        }
      }
      break;

    case 'b':                                                    /* match bk */
      if (secondChar == 'k') ret = &st->bk;
      break;

    case 'd':                                                    /* match dp */
      if (secondChar == 'p') ret = &st->dp;
      break;

    case 'i':                                           /* match ir0 and ir1 */
      if (secondChar == 'r') {
        if (thirdChar == '0') ret = &st->ir0;
        else if (thirdChar == '1') ret = &st->ir1;
      }
      else if(secondChar == 'e')
        ret = &st->ie;
      break;

    case 'p':                                                    /* match pc */
      if (secondChar == 'c') ret = &st->pc;
        break;

    case 'r':                            /* match r0-r7, rc, re, rs, rx0-rx7 */
      switch (secondChar) {
        case '0':
          ret = &st->Sregs[__r0];
          break;
        case '1':
          ret = &st->Sregs[__r1];
          break;
        case '2':
          ret = &st->Sregs[__r2];
          break;
        case '3':
          ret = &st->Sregs[__r3];
          break;
        case '4':
          ret = &st->Sregs[__r4];
          break;
        case '5':
          ret = &st->Sregs[__r5];
          break;
        case '6':
          ret = &st->Sregs[__r6];
          break;
        case '7':
          ret = &st->Sregs[__r7];
          break;
        case 'c':
          ret = &st->rc;
          break;
        case 'e':
          ret = &st->re;
          break;
        case 's':
          ret = &st->rs;
          break;
        case 'x':
          switch (thirdChar) {
            case '0':
              ret = &st->Sregs[__rx0];
              break;
            case '1':
              ret = &st->Sregs[__rx1];
              break;
            case '2':
              ret = &st->Sregs[__rx2];
              break;
            case '3':
              ret = &st->Sregs[__rx3];
              break;
            case '4':
              ret = &st->Sregs[__rx4];
              break;
            case '5':
              ret = &st->Sregs[__rx5];
              break;
            case '6':
              ret = &st->Sregs[__rx6];
              break;
            case '7':
              ret = &st->Sregs[__rx7];
              break;
          }
      }
    case 's':                                                 /* match st,sp */
      if (secondChar == 't') ret = &st->st;
      else if (secondChar == 'p') ret = &st->sp;
      break;
  }

  return ret;
}
