OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [scarts_32/] [scarts_32-iss.c] - Rev 26

Compare with Previous | Blame | View Log

/* SCARTS (32-bit) target-dependent code for the GNU simulator.
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
   Free Software Foundation, Inc.
   Contributed by Martin Walter <mwalter@opencores.org>
 
   This file is part of the GNU simulators.
 
   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 3 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.
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#define GNU_SOURCE
#define _GNU_SOURCE
 
#ifndef PARAMS
#define PARAMS(ARGS) ARGS
#endif
 
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
 
#include "modules.h"
#include "scarts_32-codemem.h"
#include "scarts_32-datamem.h"
#include "scarts_32-iss.h"
#include "scarts_32-mad.h"
#include "scarts-op.h"
#include "scarts_32-plugins.h"
#include "scarts_32-desc.h"
#include "scarts_32-tdep.h"
 
/* Macros for mapping the Processor Control Module plugin registers. */
#undef PROC_CTRL_STATUS_C
#define PROC_CTRL_STATUS_C      (*(uint8_t *const)  (plugin_proc_ctrl->get_mem() + PROC_CTRL_STATUS_C_BOFF))
#undef PROC_CTRL_CONFIG_C
#define PROC_CTRL_CONFIG_C      (*(uint8_t *const)  (plugin_proc_ctrl->get_mem() + PROC_CTRL_CONFIG_C_BOFF))
#undef PROC_CTRL_INTPROT
#define PROC_CTRL_INTPROT       (*(uint16_t *const) (plugin_proc_ctrl->get_mem() + PROC_CTRL_INTPROT_BOFF))
#undef PROC_CTRL_INTMASK
#define PROC_CTRL_INTMASK       (*(uint16_t *const) (plugin_proc_ctrl->get_mem() + PROC_CTRL_INTMASK_BOFF))
#undef PROC_CTRL_FPW
#define PROC_CTRL_FPW           (*(uint32_t *const) (plugin_proc_ctrl->get_mem() + PROC_CTRL_FPW_BOFF))
#undef PROC_CTRL_FPX
#define PROC_CTRL_FPX           (*(uint32_t *const) (plugin_proc_ctrl->get_mem() + PROC_CTRL_FPX_BOFF))
#undef PROC_CTRL_FPY
#define PROC_CTRL_FPY           (*(uint32_t *const) (plugin_proc_ctrl->get_mem() + PROC_CTRL_FPY_BOFF))
#undef PROC_CTRL_FPZ
#define PROC_CTRL_FPZ           (*(uint32_t *const) (plugin_proc_ctrl->get_mem() + PROC_CTRL_FPZ_BOFF))
#undef PROC_CTRL_SAVE_STATUS_C
#define PROC_CTRL_SAVE_STATUS_C (*(uint8_t *const)  (plugin_proc_ctrl->get_mem() + PROC_CTRL_SAVE_STATUS_C_BOFF))
#undef PROGRAMMER_CONFIG_C
#define PROGRAMMER_CONFIG_C     (*(uint8_t *const)  (plugin_programmer->get_mem() + PROGRAMMER_CONFIG_C_BOFF))
 
 
static int32_t          cond;
static int32_t          carry, old_carry;
static uint32_t         regfile[SCARTS_TOTAL_NUM_REGS];
static uint32_t         vectab[SCARTS_NUM_VECTORS];
static scarts_plugin_t *plugin_programmer;
static scarts_plugin_t *plugin_proc_ctrl;
 
static int is_addr_aligned (uint32_t addr, uint8_t alignment);
static int load_data       (uint32_t addr, uint32_t *data, enum scarts_access_mode mode);
static int store_data      (uint32_t addr, uint32_t data, enum scarts_access_mode mode);
 
static int
is_addr_aligned (uint32_t addr, uint8_t alignment)
{
  if ((addr % alignment) != 0)
  {
    error ("Unaligned memory access at 0x%X", addr);
    return 0;
  }
 
  return 1;
}
 
static int
load_data (uint32_t vma, uint32_t* data, enum scarts_access_mode mode)
{
  int i;
  uint8_t size, temp;
  uint32_t addr, result;
  scarts_datamem_read_fptr_t read_fptr;
  scarts_datamem_write_fptr_t write_fptr;
  enum scarts_mem_type mem_type;
 
  result = *data = 0;
 
  switch (mode)
  {
    case WORD:
    {
      if (!is_addr_aligned (vma, SCARTS_WORD_SIZE))
        return SIGBUS;
 
      size = 4;
      break;
    }
    case HWORD:
    case HWORDU:
    {
      if (!is_addr_aligned (vma, SCARTS_WORD_SIZE / 2))
        return SIGBUS;
 
      size = 2;
      break;
    }
    case BYTE:
    case BYTEU:
    {
      size = 1;
      break;
    }
    default:
    {
      error ("Unsupported access mode.");
      return SIGILL;
    }
  }
 
  mem_type = scarts_datamem_vma_decode (vma, &read_fptr, &write_fptr, &addr);
  if (mem_type == SCARTS_NOMEM)
  {
    error ("Memory access at 0x%X is out of bounds.", vma);
    return SIGSEGV;
  }
 
  for (i = 0; i < size; ++i)
  {
    (void) (*read_fptr) (addr + i, &temp);
    result |= temp << (i * 8);
  }
 
  *data = result;
  return 0;
}
 
static int
store_data (uint32_t vma, uint32_t data, enum scarts_access_mode mode)
{
  int i;
  uint8_t size;
  uint32_t addr;
  scarts_datamem_read_fptr_t read_fptr;
  scarts_datamem_write_fptr_t write_fptr;
  enum scarts_mem_type mem_type;
 
  switch (mode)
  {
    case WORD:
    {
      if (!is_addr_aligned (vma, SCARTS_WORD_SIZE))
        return SIGBUS;
 
      size = 4;
      break;
    }
    case HWORD:
    case HWORDU:
    {
      if (!is_addr_aligned (vma, SCARTS_WORD_SIZE / 2))
        return SIGBUS;
 
      size = 2;
      break;
    }
    case BYTE:
    case BYTEU:
    {
      size = 1;
      break;
    }
    default:
    {
      error ("Unsupported access mode.");
      return SIGILL;
    }
  }
 
  mem_type = scarts_datamem_vma_decode (vma, &read_fptr, &write_fptr, &addr);
  if (mem_type == SCARTS_NOMEM)
  {
    error ("Memory access at 0x%X is out of bounds.", vma);
    return SIGSEGV;
  }
 
  for (i = 0; i < size; ++i)
  {
    (void) (*write_fptr) (addr + i, (uint8_t) (data >> (i * 8)));
  }
 
  return 0;
}
 
void
scarts_init (void)
{
  scarts_load_plugins ();
  plugin_programmer = scarts_get_plugin (PROGRAMMER_BADDR);
  if (plugin_programmer != NULL)
  {
    if (plugin_programmer->set_codemem_read_fptr == NULL)
    {
      /* Function 'set_codemem_read_fptr' is mandatory for the Programmer Module plugin. */
      error ("Unable to find function 'set_codemem_read_fptr' in Programmer Module plugin.");
      exit (EXIT_FAILURE);
    }
 
    plugin_programmer->set_codemem_read_fptr (scarts_codemem_read);
 
    if (plugin_programmer->set_codemem_write_fptr == NULL)
    {
      /* Function 'set_codemem_write_fptr' is mandatory for the Programmer Module plugin. */
      error ("Unable to find function 'set_codemem_write_fptr' in Programmer Module plugin.");
      exit (EXIT_FAILURE);
    }
 
    plugin_programmer->set_codemem_write_fptr (scarts_codemem_write);
 
    if (plugin_programmer->set_datamem_read_fptr == NULL)
    {
      /* Function 'set_datamem_read_fptr' is mandatory for the Programmer Module plugin. */
      error ("Unable to find function 'set_datamem_read_fptr' in Programmer Module plugin.");
      exit (EXIT_FAILURE);
    }
 
    plugin_programmer->set_datamem_read_fptr (scarts_datamem_read);
 
    if (plugin_programmer->set_datamem_write_fptr == NULL)
    {
      /* Function 'set_datamem_write_fptr' is mandatory for the Programmer Module plugin. */
      error ("Unable to find function 'set_datamem_write_fptr' in Programmer Module plugin.");
      exit (EXIT_FAILURE);
    }
 
    plugin_programmer->set_datamem_write_fptr (scarts_datamem_write);
  }
 
  plugin_proc_ctrl = scarts_get_plugin (PROC_CTRL_BADDR);
  if (plugin_proc_ctrl == NULL)
  {
    /* The System Control Module plugin is mandatory. */
    error ("Unable to find System Control Module plugin.");
    exit (EXIT_FAILURE);
  }
 
  scarts_bootmem_init ();
  regfile[SCARTS_PC_REGNUM] = SCARTS_BOOTMEM_VMA;
}
 
int
scarts_mem_read (uint32_t lma, uint8_t* value)
{
  uint16_t temp;
  uint32_t addr;
  scarts_codemem_read_fptr_t codemem_read_fptr;
  scarts_codemem_write_fptr_t codemem_write_fptr;
  scarts_datamem_read_fptr_t datamem_read_fptr;
  scarts_datamem_write_fptr_t datamem_write_fptr;
  enum scarts_mem_type mem_type;
 
  mem_type = scarts_lma_decode (lma,
                                &codemem_read_fptr,
                                &codemem_write_fptr,
                                &datamem_read_fptr,
                                &datamem_write_fptr,
                                &addr);
 
  if (mem_type == SCARTS_NOMEM)
  {
    /* If the LMA could not be decoded properly, the following scenario might
       have occurred: the GDB has passed the VMA of a function pointer whose
       address got determined from the data memory beforehand. */
    mem_type = scarts_codemem_vma_decode (lma * SCARTS_INSN_SIZE,
                                          &codemem_read_fptr,
                                          &codemem_write_fptr,
                                          &addr);
 
    if (mem_type == SCARTS_NOMEM)
    {
      error ("Memory access at 0x%X is out of bounds.", lma);
      return SIGSEGV;
    }
  }
 
  switch (mem_type)
  {
    case SCARTS_BOOTMEM:
    case SCARTS_CODEMEM:
    {
      if ((*codemem_read_fptr) (addr, &temp) == 0)
        return 0;
 
      if ((lma & 1) == 0)
        *value = temp & 0x00FF;
      else
        *value = (temp >> 8) & 0x00FF;
 
      break;
    }
    default:
      break;
  }
 
  switch (mem_type)
  {
    case SCARTS_DATAMEM:
    case SCARTS_PLUGIN:
    {
      if ((*datamem_read_fptr) (addr, value) == 0)
        return 0;
 
      break;
    }
    default:
      break;
  }
 
  return 1;
}
 
int
scarts_mem_write (uint32_t lma, uint8_t value)
{
  uint16_t temp;
  uint32_t addr;
  scarts_codemem_read_fptr_t codemem_read_fptr;
  scarts_codemem_write_fptr_t codemem_write_fptr;
  scarts_datamem_read_fptr_t datamem_read_fptr;
  scarts_datamem_write_fptr_t datamem_write_fptr;
  enum scarts_mem_type mem_type;
 
  mem_type = scarts_lma_decode (lma,
                                &codemem_read_fptr,
                                &codemem_write_fptr,
                                &datamem_read_fptr,
                                &datamem_write_fptr,
                                &addr);
 
  if (mem_type == SCARTS_NOMEM)
  {
    error ("Memory access at 0x%X is out of bounds.", lma);
    return SIGSEGV;
  }
 
  switch (mem_type)
  {
    case SCARTS_BOOTMEM:
    case SCARTS_CODEMEM:
    {
      if ((*codemem_read_fptr) (addr, &temp) == 0)
        return 0;
 
      if ((lma & 1) == 0)
      {
        temp &= 0xFF00;
        temp |= value;
      }
      else
      {
        temp &= 0x00FF;
        temp |= (value << 8);
      }
 
      (*codemem_write_fptr) (addr, temp);
      break;
    }
    default:
      break;
  }
 
  switch (mem_type)
  {
    case SCARTS_DATAMEM:
    case SCARTS_PLUGIN:
    {
      if ((*datamem_write_fptr) (addr, value) == 0)
        return 0;
 
      break;
    }
    default:
      break;
  }
 
  return 1;
}
 
uint32_t
scarts_regfile_read (int regno)
{
  if (regno >= 0 && regno < SCARTS_NUM_GP_REGS)
  {
    return regfile[regno];
  }
  else if (regno >= SCARTS_NUM_GP_REGS && regno < SCARTS_TOTAL_NUM_REGS)
  {
    switch (regno)
    {
      case SCARTS_FP_REGNUM:
        return PROC_CTRL_FPY;
      case SCARTS_SP_REGNUM:
        return PROC_CTRL_FPZ;
      default:
        return regfile[regno];
    }
  }
}
 
void
scarts_regfile_write (int regno, uint32_t value)
{
  if (regno >= 0 && regno < SCARTS_NUM_GP_REGS)
  {
    regfile[regno] = value;
  }
  else if (regno >= SCARTS_NUM_GP_REGS && regno < SCARTS_TOTAL_NUM_REGS)
  {
    switch (regno)
    {
      case SCARTS_FP_REGNUM:
        PROC_CTRL_FPY = value;
        break;
      case SCARTS_SP_REGNUM:
        PROC_CTRL_FPZ = value;
        break;
      default:
        regfile[regno] = value;
        break;
    }
  }
}
 
void
scarts_reset (void)
{
  uint32_t old_pc;
 
  cond = 0;
  carry = old_carry = 0;
  old_pc = regfile[SCARTS_PC_REGNUM];
 
  memset (regfile, 0, SCARTS_WORD_SIZE * SCARTS_TOTAL_NUM_REGS);
  memset (vectab, 0, SCARTS_WORD_SIZE * SCARTS_NUM_VECTORS);
  scarts_reset_plugins ();
 
  regfile[SCARTS_PC_REGNUM] = old_pc;
}
 
int
scarts_tick (void)
{
  int i, int_num, decode_steps, result;
  uint16_t unmasked_ints;
  uint32_t data;
  uint32_t addr, next_pc, *pc;
  scarts_codemem_read_fptr_t read_fptr;
  scarts_codemem_write_fptr_t write_fptr;
  scarts_op_t insn;
  enum scarts_mem_type mem_type;
 
  decode_steps = result = 0;
  data = 0;
  pc = &(regfile[SCARTS_PC_REGNUM]);
 
  if (plugin_programmer != NULL)
  {
    /* Check if the programmer module issued a soft-reset. */
    if ((PROGRAMMER_CONFIG_C & (1 << PROGRAMMER_CONFIG_C_CLR)))
      scarts_reset ();
  }
 
  next_pc = *pc;
 
  /* Call tick() for each plugin. */
  scarts_tick_plugins (pc);
 
  /* Check if a plugin requested an interrupt. */
  int_num = scarts_get_plugin_int_request ();
  if (int_num != -1)
  {
    /* Set interrupt bit in the Processor Control Module. */
    PROC_CTRL_INTPROT |= (1 << int_num);
  }
 
  /* Check for pending interrupts (INT0 is non-maskable). */
  unmasked_ints = PROC_CTRL_INTPROT & ((~PROC_CTRL_INTMASK) | 1);
 
  /* Check if the GIE flag is set in the config register. */
  if ((PROC_CTRL_CONFIG_C & (1 << PROC_CTRL_CONFIG_C_GIE)) && unmasked_ints != 0)
  {
    /* There is at least one interrupt pending and not masked. */
    int_num = 0;
    while (!(unmasked_ints & 1))
    {
      unmasked_ints >>= 1;
      int_num++;
    }
 
    /* De-protocol the interrupt in the protocol register. */
    PROC_CTRL_INTPROT &= ~(1 << int_num);
 
    /* Save the status register. */
    PROC_CTRL_SAVE_STATUS_C = PROC_CTRL_STATUS_C;
 
    /* Save the PC as return address for the RTE instruction. */
    regfile[SCARTS_RTE_REGNUM] = *pc;
 
    /* Disable the GIE flag in the config register. */
    PROC_CTRL_CONFIG_C &= ~(1 << PROC_CTRL_CONFIG_C_GIE);
 
    /* Jump to the ISR. */
    next_pc = *pc = vectab[int_num];
  }
 
  mem_type = scarts_codemem_vma_decode (*pc, &read_fptr, &write_fptr, &addr);
  if (mem_type == SCARTS_NOMEM)
  {
     error ("Memory access at 0x%X is out of bounds.", *pc);
     return SIGSEGV;
  }
 
  (void) (*read_fptr) (addr, &insn.raw);
 
  switch (insn.ldiop.op)
  {
    case OPC4_LDLI:
      regfile[insn.ldiop.reg] = insn.ldiop.val;
      break;
    case OPC4_LDHI:
      regfile[insn.ldiop.reg] &= 0xFF;
      regfile[insn.ldiop.reg] |= (int32_t) insn.ldiop.val << 8;
      assert(((regfile[insn.ldiop.reg] & 0xFFFF8000) == 0xFFFF8000) || ((regfile[insn.ldiop.reg] & 0xFFFF8000) == 0));
      break;
    case OPC4_LDLIU:
      regfile[insn.ldiop.reg] &= 0xFFFFFF00;
      regfile[insn.ldiop.reg] |= insn.ldiop.val & 0xFF;
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.imm7op.op)
  {
    case OPC5_CMPI_LT:
      cond = ((int32_t) regfile[insn.imm7op.reg] < (int32_t) insn.imm7op.val);
      break;
    case OPC5_CMPI_GT:
      cond = ((int32_t) regfile[insn.imm7op.reg] > (int32_t) insn.imm7op.val);
      break;
    case OPC5_CMPI_EQ:
      cond = ((int32_t) regfile[insn.imm7op.reg] == (int32_t) insn.imm7op.val);
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.imm6op.op)
  {
    case OPC6_LDFPW:
      if (result = load_data (PROC_CTRL_FPW + SCARTS_WORD_SIZE * insn.imm6op.val, &data, WORD))
        break;
 
      regfile[insn.imm6op.reg] = data;
      break;
    case OPC6_LDFPX:
      if (result = load_data (PROC_CTRL_FPX + SCARTS_WORD_SIZE * insn.imm6op.val, &data, WORD))
        break;
 
      regfile[insn.imm6op.reg] = data;
      break;
    case OPC6_LDFPY:
      if (result = load_data (PROC_CTRL_FPY + SCARTS_WORD_SIZE * insn.imm6op.val, &data, WORD))
        break;
 
      regfile[insn.imm6op.reg] = data;
      break;
    case OPC6_LDFPZ:
      if (result = load_data (PROC_CTRL_FPZ + SCARTS_WORD_SIZE * insn.imm6op.val, &data, WORD))
        break;
 
      regfile[insn.imm6op.reg] = data;
      break;
    case OPC6_STFPW:
      result = store_data (PROC_CTRL_FPW + SCARTS_WORD_SIZE * insn.imm6op.val, regfile[insn.imm6op.reg], WORD);
      break;
    case OPC6_STFPX:
      result = store_data (PROC_CTRL_FPX + SCARTS_WORD_SIZE * insn.imm6op.val, regfile[insn.imm6op.reg], WORD);
      break;
    case OPC6_STFPY:
      result = store_data (PROC_CTRL_FPY + SCARTS_WORD_SIZE * insn.imm6op.val, regfile[insn.imm6op.reg], WORD);
      break;
    case OPC6_STFPZ:
      result = store_data (PROC_CTRL_FPZ + SCARTS_WORD_SIZE * insn.imm6op.val, regfile[insn.imm6op.reg], WORD);
      break;
    case OPC6_ADDI:
      carry = ((int64_t) regfile[insn.imm6op.reg] + (int64_t) insn.imm6op.val) >> 32;
      regfile[insn.imm6op.reg] += insn.imm6op.val;
      break;
    case OPC6_ADDI_CT:
      if (cond)
      {
        carry = ((int64_t) regfile[insn.imm6op.reg] + (int64_t) insn.imm6op.val) >> 32;
        regfile[insn.imm6op.reg] += insn.imm6op.val;
      }
      break;
    case OPC6_ADDI_CF:
      if (!cond)
      {
        carry = ((int64_t) regfile[insn.imm6op.reg] + (int64_t) insn.imm6op.val) >> 32;
        regfile[insn.imm6op.reg] += insn.imm6op.val;
      }
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.imm5op.op)
  {
    case OPC7_LDFPW_INC:
      if (result = load_data (PROC_CTRL_FPW + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPW += SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPW_DEC:
      if (result = load_data (PROC_CTRL_FPW + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPW -= SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPX_INC:
      if (result = load_data (PROC_CTRL_FPX + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPX += SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPX_DEC:
      if (result = load_data (PROC_CTRL_FPX + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPX -= SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPY_INC:
      if (result = load_data (PROC_CTRL_FPY + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPY += SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPY_DEC:
      if (result = load_data (PROC_CTRL_FPY + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPY -= SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPZ_INC:
      if (result = load_data (PROC_CTRL_FPZ + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPZ += SCARTS_WORD_SIZE;
      break;
    case OPC7_LDFPZ_DEC:
      if (result = load_data (PROC_CTRL_FPZ + SCARTS_WORD_SIZE * insn.imm5op.val, &data, WORD))
        break;
 
      regfile[insn.imm5op.reg] = data;
      PROC_CTRL_FPZ -= SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPW_INC:
      if (result = store_data (PROC_CTRL_FPW + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPW += SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPW_DEC:
      if (result = store_data (PROC_CTRL_FPW + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPW -= SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPX_INC:
      if (result = store_data (PROC_CTRL_FPX + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPX += SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPX_DEC:
      if (result = store_data (PROC_CTRL_FPX + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPX -= SCARTS_WORD_SIZE;
    case OPC7_STFPY_INC:
      if (result = store_data (PROC_CTRL_FPY + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPY += SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPY_DEC:
      if (result = store_data (PROC_CTRL_FPY + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPY -= SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPZ_INC:
      if (result = store_data (PROC_CTRL_FPZ + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPZ += SCARTS_WORD_SIZE;
      break;
    case OPC7_STFPZ_DEC:
      if (result = store_data (PROC_CTRL_FPZ + SCARTS_WORD_SIZE * insn.imm5op.val, regfile[insn.imm5op.reg], WORD))
        break;
 
      PROC_CTRL_FPZ -= SCARTS_WORD_SIZE;
      break;
    case OPC7_BSET:
      regfile[insn.imm5op.reg] |= 1 << (uint32_t) insn.imm5op.val;
      break;
    case OPC7_BCLR:
      regfile[insn.imm5op.reg] &= ~(1 << (uint32_t) insn.imm5op.val);
      break;
    case OPC7_BSET_CT:
      if (cond)
      {
        regfile[insn.imm5op.reg] |= 1 << (uint32_t) insn.imm5op.val;
      }
      break;
    case OPC7_BCLR_CT:
      if (cond)
      {
        regfile[insn.imm5op.reg] &= ~(1 << (uint32_t) insn.imm5op.val);
      }
      break;
    case OPC7_BSET_CF:
      if (!cond)
      {
        regfile[insn.imm5op.reg] |= 1 << (uint32_t) insn.imm5op.val;
      }
      break;
    case OPC7_BCLR_CF:
      if (!cond)
      {
        regfile[insn.imm5op.reg] &= ~(1 << (uint32_t) insn.imm5op.val);
      }
      break;
    case OPC7_BTEST:
      cond = ((regfile[insn.imm5op.reg] & (1 << (uint32_t) insn.imm5op.val)) != 0);
      break;
    case OPC7_STVEC:
      vectab[insn.imm5op.val + 16] = regfile[insn.imm5op.reg];
      break;
    case OPC7_LDVEC:
      regfile[insn.imm5op.reg] = vectab[insn.imm5op.val + 16];
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.imm4op.op)
  {
    case OPC8_SLI:
      carry = (regfile[insn.imm4op.reg] >> (32 - (uint32_t) insn.imm4op.val)) & 1;
      regfile[insn.imm4op.reg] <<= (uint32_t) insn.imm4op.val;
      break;
    case OPC8_SRI:
      carry = regfile[insn.imm4op.reg] & (1 << ((uint32_t) insn.imm4op.val - 1));
      regfile[insn.imm4op.reg] >>= (uint32_t) insn.imm4op.val;
      break;
    case OPC8_SRAI:
      carry = regfile[insn.imm4op.reg] & (1 << ((uint32_t) insn.imm4op.val - 1));
      regfile[insn.imm4op.reg] = (int32_t) regfile[insn.imm4op.reg] >> (uint32_t) insn.imm4op.val;
      break;
    case OPC8_TRAP:
      regfile[SCARTS_RTE_REGNUM] = *pc + SCARTS_INSN_SIZE;
      next_pc = vectab[insn.imm4op.val + 16] - SCARTS_INSN_SIZE;
      break;
    case OPC8_SLI_CT:
      if (cond)
      {
        carry = (regfile[insn.imm4op.reg] >> (32 - (uint32_t) insn.imm4op.val)) & 1;
        regfile[insn.imm4op.reg] <<= (uint32_t) insn.imm4op.val;
      }
      break;
    case OPC8_SRI_CT:
      if (cond)
      {
        carry = regfile[insn.imm4op.reg] & (1 << ((uint32_t) insn.imm4op.val - 1));
        regfile[insn.imm4op.reg] >>= (uint32_t) insn.imm4op.val;
      }
      break;
    case OPC8_SRAI_CT:
      if (cond)
      {
        carry = regfile[insn.imm4op.reg] & (1 << ((uint32_t) insn.imm4op.val - 1));
        regfile[insn.imm4op.reg] = (int32_t) regfile[insn.imm4op.reg] >> (uint32_t) insn.imm4op.val;
      }
      break;
    case OPC8_TRAP_CT:
      if (cond)
      {
        regfile[SCARTS_RTE_REGNUM] = *pc + SCARTS_INSN_SIZE;
        next_pc = vectab[insn.imm4op.val + 16] - SCARTS_INSN_SIZE;
      }
      break;
    case OPC8_SLI_CF:
      if (!cond)
      {
        carry = (regfile[insn.imm4op.reg] >> (32 - (uint32_t) insn.imm4op.val)) & 1;
        regfile[insn.imm4op.reg] <<= (uint32_t) insn.imm4op.val;
      }
      break;
    case OPC8_SRI_CF:
      if (!cond)
      {
        carry = regfile[insn.imm4op.reg] & (1 << ((uint32_t) insn.imm4op.val - 1));
        regfile[insn.imm4op.reg] >>= (uint32_t) insn.imm4op.val;
      }
      break;
    case OPC8_SRAI_CF:
      if (!cond)
      {
        carry = regfile[insn.imm4op.reg] & (1 << ((uint32_t) insn.imm4op.val - 1));
        regfile[insn.imm4op.reg] = (int32_t) regfile[insn.imm4op.reg] >> (uint32_t) insn.imm4op.val;
      }
      break;
    case OPC8_TRAP_CF:
      if (!cond)
      {
        regfile[SCARTS_RTE_REGNUM] = *pc + SCARTS_INSN_SIZE;
        next_pc = vectab[insn.imm4op.val + 16] - SCARTS_INSN_SIZE;
      }
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.binop.op)
  {
    case OPC8_SL:
      carry = (regfile[insn.binop.reg1] >> (32 - regfile[insn.binop.reg2])) & 1;
      regfile[insn.binop.reg1] <<= regfile[insn.binop.reg2];
      break;
    case OPC8_SR:
      carry = regfile[insn.binop.reg1] & (1 << (regfile[insn.binop.reg2] - 1));
      regfile[insn.binop.reg1] >>= regfile[insn.binop.reg2];
      break;
    case OPC8_SRA:
      carry = regfile[insn.binop.reg1] & (1 << (regfile[insn.binop.reg2] - 1));
      regfile[insn.binop.reg1] = (int32_t) regfile[insn.binop.reg1] >> regfile[insn.binop.reg2];
      break;
    case OPC8_SL_CT:
      if (cond)
      {
        carry = (regfile[insn.binop.reg1] >> (32 - regfile[insn.binop.reg2])) & 1;
        regfile[insn.binop.reg1] <<= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SR_CT:
      if (cond)
      {
        carry = regfile[insn.binop.reg1] & (1 << (regfile[insn.binop.reg2] - 1));
        regfile[insn.binop.reg1] >>= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SRA_CT:
      if (cond)
      {
        carry = regfile[insn.binop.reg1] & (1 << (regfile[insn.binop.reg2] - 1));
        regfile[insn.binop.reg1] = (int32_t) regfile[insn.binop.reg1] >> regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SL_CF:
      if (!cond)
      {
        carry = (regfile[insn.binop.reg1] >> (32 - regfile[insn.binop.reg2])) & 1;
        regfile[insn.binop.reg1] <<= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SR_CF:
      if (!cond)
      {
        carry = regfile[insn.binop.reg1] & (1 << (regfile[insn.binop.reg2] - 1));
        regfile[insn.binop.reg1] >>= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SRA_CF:
      if (!cond)
      {
        carry = regfile[insn.binop.reg1] & (1 << (regfile[insn.binop.reg2] - 1));
        regfile[insn.binop.reg1] = (int32_t) regfile[insn.binop.reg1] >> regfile[insn.binop.reg2];
      }
      break;
    case OPC8_CMP_EQ:
      cond = (regfile[insn.binop.reg1] == regfile[insn.binop.reg2]);
      break;
    case OPC8_CMP_LT:
      cond = ((int32_t) regfile[insn.binop.reg1] < (int32_t) regfile[insn.binop.reg2]);
      break;
    case OPC8_CMP_GT:
      cond = ((int32_t) regfile[insn.binop.reg1] > (int32_t) regfile[insn.binop.reg2]);
      break;
    case OPC8_CMPU_LT:
      cond = ((uint32_t) regfile[insn.binop.reg1] < (uint32_t) regfile[insn.binop.reg2]);
      break;
    case OPC8_CMPU_GT:
      cond = ((uint32_t) regfile[insn.binop.reg1] > (uint32_t) regfile[insn.binop.reg2]);
      break;
    case OPC8_MOV:
      regfile[insn.binop.reg1] = regfile[insn.binop.reg2];
      break;
    case OPC8_ADD:
      carry = ((int64_t) regfile[insn.binop.reg1] + (int64_t) regfile[insn.binop.reg2]) >> 32;
      regfile[insn.binop.reg1] += regfile[insn.binop.reg2];
      break;
    case OPC8_ADDC:
      old_carry = carry;
      carry = ((int64_t) regfile[insn.binop.reg1] + (int64_t) regfile[insn.binop.reg2] + old_carry) >> 32;
      regfile[insn.binop.reg1] += regfile[insn.binop.reg2] + old_carry;
      break;
    case OPC8_SUB:
      carry = ((int64_t) regfile[insn.binop.reg1] - (int64_t) regfile[insn.binop.reg2]) >> 32;
      regfile[insn.binop.reg1] -= regfile[insn.binop.reg2];
      break;
    case OPC8_SUBC:
      old_carry = carry;
      carry = ((int64_t) regfile[insn.binop.reg1] - (int64_t) regfile[insn.binop.reg2] - old_carry) >> 32;
      regfile[insn.binop.reg1] -= regfile[insn.binop.reg2] + old_carry;
      break;
    case OPC8_AND:
      regfile[insn.binop.reg1] &= regfile[insn.binop.reg2];
      break;
    case OPC8_OR:
      regfile[insn.binop.reg1] |= regfile[insn.binop.reg2];
      break;
    case OPC8_EOR:
      regfile[insn.binop.reg1] ^= regfile[insn.binop.reg2];
      break;
    case OPC8_MOV_CT:
      if (cond)
      {
        regfile[insn.binop.reg1] = regfile[insn.binop.reg2];
      }
      break;
    case OPC8_ADD_CT:
      if (cond)
      {
        carry = ((int64_t) regfile[insn.binop.reg1] + (int64_t) regfile[insn.binop.reg2]) >> 32;
        regfile[insn.binop.reg1] += regfile[insn.binop.reg2];
      }
      break;
    case OPC8_ADDC_CT:
      if (cond)
      {
        old_carry = carry;
        carry = ((int64_t) regfile[insn.binop.reg1] + (int64_t) regfile[insn.binop.reg2] + old_carry) >> 32;
        regfile[insn.binop.reg1] += regfile[insn.binop.reg2] + old_carry;
      }
      break;
    case OPC8_SUB_CT:
      if (cond)
      {
        carry = ((int64_t) regfile[insn.binop.reg1] - (int64_t) regfile[insn.binop.reg2]) >> 32;
        regfile[insn.binop.reg1] -= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SUBC_CT:
      if (cond)
      {
        old_carry = carry;
        carry = ((int64_t) regfile[insn.binop.reg1] - (int64_t) regfile[insn.binop.reg2] - old_carry) >> 32;
        regfile[insn.binop.reg1] -= regfile[insn.binop.reg2] + old_carry;
      }
      break;
    case OPC8_AND_CT:
      if (cond)
      {
        regfile[insn.binop.reg1] &= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_OR_CT:
      if (cond)
      {
        regfile[insn.binop.reg1] |= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_EOR_CT:
      if (cond)
      {
        regfile[insn.binop.reg1] ^= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_MOV_CF:
      if (!cond)
      {
        regfile[insn.binop.reg1] = regfile[insn.binop.reg2];
      }
      break;
    case OPC8_ADD_CF:
      if (!cond)
      {
        carry = ((int64_t) regfile[insn.binop.reg1] + (int64_t) regfile[insn.binop.reg2]) >> 32;
        regfile[insn.binop.reg1] += regfile[insn.binop.reg2];
      }
      break;
    case OPC8_ADDC_CF:
      if (!cond)
      {
        old_carry = carry;
        carry = ((int64_t) regfile[insn.binop.reg1] + (int64_t) regfile[insn.binop.reg2] + old_carry) >> 32;
        regfile[insn.binop.reg1] += regfile[insn.binop.reg2] + old_carry;
      }
      break;
    case OPC8_SUB_CF:
      if (!cond)
      {
        carry = ((int64_t)regfile[insn.binop.reg1] - (int64_t)regfile[insn.binop.reg2]) >> 32;
        regfile[insn.binop.reg1] -= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_SUBC_CF:
      if (!cond)
      {
        old_carry = carry;
        carry = ((int64_t) regfile[insn.binop.reg1] - (int64_t) regfile[insn.binop.reg2] - old_carry) >> 32;
        regfile[insn.binop.reg1] -= regfile[insn.binop.reg2] + old_carry;
      }
      break;
    case OPC8_AND_CF:
      if (!cond)
      {
        regfile[insn.binop.reg1] &= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_OR_CF:
      if (!cond)
      {
        regfile[insn.binop.reg1] |= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_EOR_CF:
      if (!cond)
      {
        regfile[insn.binop.reg1] ^= regfile[insn.binop.reg2];
      }
      break;
    case OPC8_LDW:
      if (result = load_data (regfile[insn.binop.reg2], &data, WORD))
        break;
 
      regfile[insn.binop.reg1] = data;
      break;
    case OPC8_LDH:
      if (result = load_data (regfile[insn.binop.reg2], &data, HWORD))
        break;
 
      regfile[insn.binop.reg1] = data;
      break;
    case OPC8_LDHU:
      if (result = load_data (regfile[insn.binop.reg2], &data, HWORDU))
        break;
 
      regfile[insn.binop.reg1] = data;
      break;
    case OPC8_LDB:
      if (result = load_data (regfile[insn.binop.reg2], &data, BYTE))
        break;
 
      regfile[insn.binop.reg1] = data;
      break;
    case OPC8_LDBU:
      if (result = load_data (regfile[insn.binop.reg2], &data, BYTEU))
        break;
 
      regfile[insn.binop.reg1] = data;
      break;
    case OPC8_STW:
      result = store_data (regfile[insn.binop.reg2], regfile[insn.binop.reg1], WORD);
      break;
    case OPC8_STH:
      result = store_data (regfile[insn.binop.reg2], regfile[insn.binop.reg1], HWORD);
      break;
    case OPC8_STB:
      result = store_data (regfile[insn.binop.reg2], regfile[insn.binop.reg1], BYTE);
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.jmpiop.op)
  {
    case OPC6_JMPI:
      next_pc += (insn.jmpiop.dest * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      break;
    case OPC6_JMPI_CT:
      if (cond)
      {
        next_pc += (insn.jmpiop.dest * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      }
      break;
    case OPC6_JMPI_CF:
      if (!cond)
      {
        next_pc += (insn.jmpiop.dest * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      }
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.unop.op)
  {
    case OPC12_RRC:
      old_carry = carry;
      carry = regfile[insn.unop.reg] & 1;
      regfile[insn.unop.reg] >>= 1;
      regfile[insn.unop.reg] |= old_carry << 31;
      break;
    case OPC12_NOT:
      regfile[insn.unop.reg] = ~regfile[insn.unop.reg];
      break;
    case OPC12_NEG:
      regfile[insn.unop.reg] = -regfile[insn.unop.reg];
      break;
    case OPC12_JSR:
      regfile[SCARTS_RTS_REGNUM] = *pc + SCARTS_INSN_SIZE;
      next_pc = (regfile[insn.unop.reg] * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      break;
    case OPC12_JMP:
      next_pc = (regfile[insn.unop.reg] * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      break;
    case OPC12_RRC_CT:
      if (cond)
      {
        old_carry = carry;
        carry = regfile[insn.unop.reg] & 1;
        regfile[insn.unop.reg] >>= 1;
        regfile[insn.unop.reg] |= old_carry << 31;
      }
      break;
    case OPC12_NOT_CT:
      if (cond)
      {
        regfile[insn.unop.reg] = ~regfile[insn.unop.reg];
      }
      break;
    case OPC12_NEG_CT:
      if (cond)
      {
        regfile[insn.unop.reg] = -regfile[insn.unop.reg];
      }
      break;
    case OPC12_JSR_CT:
      if (cond)
      {
        regfile[SCARTS_RTS_REGNUM] = *pc + SCARTS_INSN_SIZE;
        next_pc = (regfile[insn.unop.reg] * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      }
      break;
    case OPC12_JMP_CT:
      if (cond)
      {
        next_pc = (regfile[insn.unop.reg] * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      }
      break;
    case OPC12_RRC_CF:
      if (!cond)
      {
        old_carry = carry;
        carry = regfile[insn.unop.reg] & 1;
        regfile[insn.unop.reg] >>= 1;
        regfile[insn.unop.reg] |= old_carry << 31;
      }
      break;
    case OPC12_NOT_CF:
      if (!cond)
      {
        regfile[insn.unop.reg] = ~regfile[insn.unop.reg];
      }
      break;
    case OPC12_NEG_CF:
      if (!cond)
      {
        regfile[insn.unop.reg] = -regfile[insn.unop.reg];
      }
      break;
    case OPC12_JSR_CF:
      if (!cond)
      {
        regfile[SCARTS_RTS_REGNUM] = *pc + SCARTS_INSN_SIZE;
        next_pc = (regfile[insn.unop.reg] * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      }
      break;
    case OPC12_JMP_CF:
      if (!cond)
      {
        next_pc = (regfile[insn.unop.reg] * SCARTS_INSN_SIZE) - SCARTS_INSN_SIZE;
      }
      break;
    default:
      decode_steps++;
  }
 
  switch (insn.nulop.op)
  {
    case OPC16_RTS:
      next_pc = regfile[SCARTS_RTS_REGNUM] - SCARTS_INSN_SIZE;
      break;
    case OPC16_RTE:
      PROC_CTRL_CONFIG_C |= (1 << PROC_CTRL_CONFIG_C_GIE);
      PROC_CTRL_STATUS_C = PROC_CTRL_SAVE_STATUS_C;
      next_pc = regfile[SCARTS_RTS_REGNUM] - SCARTS_INSN_SIZE;
      break;
    case OPC16_NOP:
      break;
    case OPC16_ILLOP:
      result = SIGILL;
      break;
    default:
      decode_steps++;
  }
 
  carry = (!!carry) & 1;
 
  /* Compute the PC. */
  *pc = next_pc;
  *pc += SCARTS_INSN_SIZE;
 
  if (decode_steps != 8)
  {
    error ("Error in decoder stage (PC: 0x%X)", *pc - SCARTS_INSN_SIZE);
    exit (EXIT_FAILURE);
  }
 
  return result;
}
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.