OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [tags/] [gdb/] [gdb-6.8/] [gdb-6.8.openrisc-2.1/] [sim/] [m68hc11/] [dv-m68hc11spi.c] - Diff between revs 24 and 33

Only display areas with differences | Details | Blame | View Log

Rev 24 Rev 33
/*  dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
/*  dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
    Copyright (C) 2000, 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
    Copyright (C) 2000, 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
    Written by Stephane Carrez (stcarrez@nerim.fr)
    Written by Stephane Carrez (stcarrez@nerim.fr)
    (From a driver model Contributed by Cygnus Solutions.)
    (From a driver model Contributed by Cygnus Solutions.)
 
 
    This file is part of the program GDB, the GNU debugger.
    This file is part of the program GDB, the GNU debugger.
 
 
    This program is free software; you can redistribute it and/or modify
    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
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    (at your option) any later version.
 
 
    This program is distributed in the hope that it will be useful,
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    GNU General Public License for more details.
 
 
    You should have received a copy of the GNU General Public License
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
    */
    */
 
 
 
 
#include "sim-main.h"
#include "sim-main.h"
#include "hw-main.h"
#include "hw-main.h"
#include "dv-sockser.h"
#include "dv-sockser.h"
#include "sim-assert.h"
#include "sim-assert.h"
 
 
 
 
/* DEVICE
/* DEVICE
 
 
        m68hc11spi - m68hc11 SPI interface
        m68hc11spi - m68hc11 SPI interface
 
 
 
 
   DESCRIPTION
   DESCRIPTION
 
 
        Implements the m68hc11 Synchronous Serial Peripheral Interface
        Implements the m68hc11 Synchronous Serial Peripheral Interface
        described in the m68hc11 user guide (Chapter 8 in pink book).
        described in the m68hc11 user guide (Chapter 8 in pink book).
        The SPI I/O controller is directly connected to the CPU
        The SPI I/O controller is directly connected to the CPU
        interrupt.  The simulator implements:
        interrupt.  The simulator implements:
 
 
            - SPI clock emulation
            - SPI clock emulation
            - Data transfer
            - Data transfer
            - Write collision detection
            - Write collision detection
 
 
 
 
   PROPERTIES
   PROPERTIES
 
 
        None
        None
 
 
 
 
   PORTS
   PORTS
 
 
   reset (input)
   reset (input)
 
 
        Reset port. This port is only used to simulate a reset of the SPI
        Reset port. This port is only used to simulate a reset of the SPI
        I/O controller. It should be connected to the RESET output of the cpu.
        I/O controller. It should be connected to the RESET output of the cpu.
 
 
   */
   */
 
 
 
 
 
 
/* port ID's */
/* port ID's */
 
 
enum
enum
{
{
  RESET_PORT
  RESET_PORT
};
};
 
 
 
 
static const struct hw_port_descriptor m68hc11spi_ports[] =
static const struct hw_port_descriptor m68hc11spi_ports[] =
{
{
  { "reset", RESET_PORT, 0, input_port, },
  { "reset", RESET_PORT, 0, input_port, },
  { NULL, },
  { NULL, },
};
};
 
 
 
 
/* SPI */
/* SPI */
struct m68hc11spi
struct m68hc11spi
{
{
  /* Information about next character to be transmited.  */
  /* Information about next character to be transmited.  */
  unsigned char tx_char;
  unsigned char tx_char;
  int           tx_bit;
  int           tx_bit;
  unsigned char mode;
  unsigned char mode;
 
 
  unsigned char rx_char;
  unsigned char rx_char;
  unsigned char rx_clear_scsr;
  unsigned char rx_clear_scsr;
  unsigned char clk_pin;
  unsigned char clk_pin;
 
 
  /* SPI clock rate (twice the real clock).  */
  /* SPI clock rate (twice the real clock).  */
  unsigned int clock;
  unsigned int clock;
 
 
  /* Periodic SPI event.  */
  /* Periodic SPI event.  */
  struct hw_event* spi_event;
  struct hw_event* spi_event;
};
};
 
 
 
 
 
 
/* Finish off the partially created hw device.  Attach our local
/* Finish off the partially created hw device.  Attach our local
   callbacks.  Wire up our port names etc */
   callbacks.  Wire up our port names etc */
 
 
static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
static hw_port_event_method m68hc11spi_port_event;
static hw_port_event_method m68hc11spi_port_event;
static hw_ioctl_method m68hc11spi_ioctl;
static hw_ioctl_method m68hc11spi_ioctl;
 
 
#define M6811_SPI_FIRST_REG (M6811_SPCR)
#define M6811_SPI_FIRST_REG (M6811_SPCR)
#define M6811_SPI_LAST_REG  (M6811_SPDR)
#define M6811_SPI_LAST_REG  (M6811_SPDR)
 
 
 
 
static void
static void
attach_m68hc11spi_regs (struct hw *me,
attach_m68hc11spi_regs (struct hw *me,
                        struct m68hc11spi *controller)
                        struct m68hc11spi *controller)
{
{
  hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
  hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
                     M6811_SPI_FIRST_REG,
                     M6811_SPI_FIRST_REG,
                     M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
                     M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
                     me);
                     me);
}
}
 
 
static void
static void
m68hc11spi_finish (struct hw *me)
m68hc11spi_finish (struct hw *me)
{
{
  struct m68hc11spi *controller;
  struct m68hc11spi *controller;
 
 
  controller = HW_ZALLOC (me, struct m68hc11spi);
  controller = HW_ZALLOC (me, struct m68hc11spi);
  set_hw_data (me, controller);
  set_hw_data (me, controller);
  set_hw_io_read_buffer (me, m68hc11spi_io_read_buffer);
  set_hw_io_read_buffer (me, m68hc11spi_io_read_buffer);
  set_hw_io_write_buffer (me, m68hc11spi_io_write_buffer);
  set_hw_io_write_buffer (me, m68hc11spi_io_write_buffer);
  set_hw_ports (me, m68hc11spi_ports);
  set_hw_ports (me, m68hc11spi_ports);
  set_hw_port_event (me, m68hc11spi_port_event);
  set_hw_port_event (me, m68hc11spi_port_event);
#ifdef set_hw_ioctl
#ifdef set_hw_ioctl
  set_hw_ioctl (me, m68hc11spi_ioctl);
  set_hw_ioctl (me, m68hc11spi_ioctl);
#else
#else
  me->to_ioctl = m68hc11spi_ioctl;
  me->to_ioctl = m68hc11spi_ioctl;
#endif
#endif
 
 
  /* Attach ourself to our parent bus.  */
  /* Attach ourself to our parent bus.  */
  attach_m68hc11spi_regs (me, controller);
  attach_m68hc11spi_regs (me, controller);
 
 
  /* Initialize to reset state.  */
  /* Initialize to reset state.  */
  controller->spi_event = NULL;
  controller->spi_event = NULL;
  controller->rx_clear_scsr = 0;
  controller->rx_clear_scsr = 0;
}
}
 
 
 
 
 
 
/* An event arrives on an interrupt port */
/* An event arrives on an interrupt port */
 
 
static void
static void
m68hc11spi_port_event (struct hw *me,
m68hc11spi_port_event (struct hw *me,
                       int my_port,
                       int my_port,
                       struct hw *source,
                       struct hw *source,
                       int source_port,
                       int source_port,
                       int level)
                       int level)
{
{
  SIM_DESC sd;
  SIM_DESC sd;
  struct m68hc11spi *controller;
  struct m68hc11spi *controller;
  sim_cpu* cpu;
  sim_cpu* cpu;
  unsigned8 val;
  unsigned8 val;
 
 
  controller = hw_data (me);
  controller = hw_data (me);
  sd         = hw_system (me);
  sd         = hw_system (me);
  cpu        = STATE_CPU (sd, 0);
  cpu        = STATE_CPU (sd, 0);
  switch (my_port)
  switch (my_port)
    {
    {
    case RESET_PORT:
    case RESET_PORT:
      {
      {
        HW_TRACE ((me, "SPI reset"));
        HW_TRACE ((me, "SPI reset"));
 
 
        /* Reset the state of SPI registers.  */
        /* Reset the state of SPI registers.  */
        controller->rx_clear_scsr = 0;
        controller->rx_clear_scsr = 0;
        if (controller->spi_event)
        if (controller->spi_event)
          {
          {
            hw_event_queue_deschedule (me, controller->spi_event);
            hw_event_queue_deschedule (me, controller->spi_event);
            controller->spi_event = 0;
            controller->spi_event = 0;
          }
          }
 
 
        val = 0;
        val = 0;
        m68hc11spi_io_write_buffer (me, &val, io_map,
        m68hc11spi_io_write_buffer (me, &val, io_map,
                                    (unsigned_word) M6811_SPCR, 1);
                                    (unsigned_word) M6811_SPCR, 1);
        break;
        break;
      }
      }
 
 
    default:
    default:
      hw_abort (me, "Event on unknown port %d", my_port);
      hw_abort (me, "Event on unknown port %d", my_port);
      break;
      break;
    }
    }
}
}
 
 
static void
static void
set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value)
set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value)
{
{
  uint8 val;
  uint8 val;
 
 
  if (value)
  if (value)
    val = cpu->ios[port] | mask;
    val = cpu->ios[port] | mask;
  else
  else
    val = cpu->ios[port] & ~mask;
    val = cpu->ios[port] & ~mask;
 
 
  /* Set the new value and post an event to inform other devices
  /* Set the new value and post an event to inform other devices
     that pin 'port' changed.  */
     that pin 'port' changed.  */
  m68hc11cpu_set_port (me, cpu, port, val);
  m68hc11cpu_set_port (me, cpu, port, val);
}
}
 
 
 
 
/* When a character is sent/received by the SPI, the PD2..PD5 line
/* When a character is sent/received by the SPI, the PD2..PD5 line
   are driven by the following signals:
   are driven by the following signals:
 
 
              B7        B6
              B7        B6
      -----+---------+--------+---/-+-------
      -----+---------+--------+---/-+-------
 MOSI      |    |    |   |    |     |
 MOSI      |    |    |   |    |     |
 MISO      +---------+--------+---/-+
 MISO      +---------+--------+---/-+
                ____      ___
                ____      ___
 CLK    _______/    \____/   \__                CPOL=0, CPHA=0
 CLK    _______/    \____/   \__                CPOL=0, CPHA=0
        _______      ____     __
        _______      ____     __
               \____/    \___/                  CPOL=1, CPHA=0
               \____/    \___/                  CPOL=1, CPHA=0
           ____      ____     __
           ____      ____     __
        __/    \____/    \___/                  CPOL=0, CPHA=1
        __/    \____/    \___/                  CPOL=0, CPHA=1
        __      ____      ___
        __      ____      ___
          \____/    \____/   \__                CPOL=1, CPHA=1
          \____/    \____/   \__                CPOL=1, CPHA=1
 
 
 SS ___                                 ____
 SS ___                                 ____
       \__________________________//___/
       \__________________________//___/
 
 
 MISO = PD2
 MISO = PD2
 MOSI = PD3
 MOSI = PD3
 SCK  = PD4
 SCK  = PD4
 SS   = PD5
 SS   = PD5
 
 
*/
*/
 
 
#define SPI_START_BYTE 0
#define SPI_START_BYTE 0
#define SPI_START_BIT  1
#define SPI_START_BIT  1
#define SPI_MIDDLE_BIT 2
#define SPI_MIDDLE_BIT 2
 
 
void
void
m68hc11spi_clock (struct hw *me, void *data)
m68hc11spi_clock (struct hw *me, void *data)
{
{
  SIM_DESC sd;
  SIM_DESC sd;
  struct m68hc11spi* controller;
  struct m68hc11spi* controller;
  sim_cpu *cpu;
  sim_cpu *cpu;
  int check_interrupt = 0;
  int check_interrupt = 0;
 
 
  controller = hw_data (me);
  controller = hw_data (me);
  sd         = hw_system (me);
  sd         = hw_system (me);
  cpu        = STATE_CPU (sd, 0);
  cpu        = STATE_CPU (sd, 0);
 
 
  /* Cleanup current event.  */
  /* Cleanup current event.  */
  if (controller->spi_event)
  if (controller->spi_event)
    {
    {
      hw_event_queue_deschedule (me, controller->spi_event);
      hw_event_queue_deschedule (me, controller->spi_event);
      controller->spi_event = 0;
      controller->spi_event = 0;
    }
    }
 
 
  /* Change a bit of data at each two SPI event.  */
  /* Change a bit of data at each two SPI event.  */
  if (controller->mode == SPI_START_BIT)
  if (controller->mode == SPI_START_BIT)
    {
    {
      /* Reflect the bit value on bit 2 of port D.  */
      /* Reflect the bit value on bit 2 of port D.  */
      set_bit_port (me, cpu, M6811_PORTD, (1 << 2),
      set_bit_port (me, cpu, M6811_PORTD, (1 << 2),
                    (controller->tx_char & (1 << controller->tx_bit)));
                    (controller->tx_char & (1 << controller->tx_bit)));
      controller->tx_bit--;
      controller->tx_bit--;
      controller->mode = SPI_MIDDLE_BIT;
      controller->mode = SPI_MIDDLE_BIT;
    }
    }
  else if (controller->mode == SPI_MIDDLE_BIT)
  else if (controller->mode == SPI_MIDDLE_BIT)
    {
    {
      controller->mode = SPI_START_BIT;
      controller->mode = SPI_START_BIT;
    }
    }
 
 
  if (controller->mode == SPI_START_BYTE)
  if (controller->mode == SPI_START_BYTE)
    {
    {
      /* Start a new SPI transfer.  */
      /* Start a new SPI transfer.  */
 
 
      /* TBD: clear SS output.  */
      /* TBD: clear SS output.  */
      controller->mode = SPI_START_BIT;
      controller->mode = SPI_START_BIT;
      controller->tx_bit = 7;
      controller->tx_bit = 7;
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), ~controller->clk_pin);
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), ~controller->clk_pin);
    }
    }
  else
  else
    {
    {
      /* Change the SPI clock at each event on bit 4 of port D.  */
      /* Change the SPI clock at each event on bit 4 of port D.  */
      controller->clk_pin = ~controller->clk_pin;
      controller->clk_pin = ~controller->clk_pin;
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
    }
    }
 
 
  /* Transmit is now complete for this byte.  */
  /* Transmit is now complete for this byte.  */
  if (controller->mode == SPI_START_BIT && controller->tx_bit < 0)
  if (controller->mode == SPI_START_BIT && controller->tx_bit < 0)
    {
    {
      controller->rx_clear_scsr = 0;
      controller->rx_clear_scsr = 0;
      cpu->ios[M6811_SPSR] |= M6811_SPIF;
      cpu->ios[M6811_SPSR] |= M6811_SPIF;
      if (cpu->ios[M6811_SPCR] & M6811_SPIE)
      if (cpu->ios[M6811_SPCR] & M6811_SPIE)
        check_interrupt = 1;
        check_interrupt = 1;
    }
    }
  else
  else
    {
    {
      controller->spi_event = hw_event_queue_schedule (me, controller->clock,
      controller->spi_event = hw_event_queue_schedule (me, controller->clock,
                                                       m68hc11spi_clock,
                                                       m68hc11spi_clock,
                                                       NULL);
                                                       NULL);
    }
    }
 
 
  if (check_interrupt)
  if (check_interrupt)
    interrupts_update_pending (&cpu->cpu_interrupts);
    interrupts_update_pending (&cpu->cpu_interrupts);
}
}
 
 
/* Flags of the SPCR register.  */
/* Flags of the SPCR register.  */
io_reg_desc spcr_desc[] = {
io_reg_desc spcr_desc[] = {
  { M6811_SPIE, "SPIE ", "Serial Peripheral Interrupt Enable" },
  { M6811_SPIE, "SPIE ", "Serial Peripheral Interrupt Enable" },
  { M6811_SPE,  "SPE  ",  "Serial Peripheral System Enable" },
  { M6811_SPE,  "SPE  ",  "Serial Peripheral System Enable" },
  { M6811_DWOM, "DWOM ", "Port D Wire-OR mode option" },
  { M6811_DWOM, "DWOM ", "Port D Wire-OR mode option" },
  { M6811_MSTR, "MSTR ", "Master Mode Select" },
  { M6811_MSTR, "MSTR ", "Master Mode Select" },
  { M6811_CPOL, "CPOL ", "Clock Polarity" },
  { M6811_CPOL, "CPOL ", "Clock Polarity" },
  { M6811_CPHA, "CPHA ", "Clock Phase" },
  { M6811_CPHA, "CPHA ", "Clock Phase" },
  { M6811_SPR1, "SPR1 ", "SPI Clock Rate Select" },
  { M6811_SPR1, "SPR1 ", "SPI Clock Rate Select" },
  { M6811_SPR0, "SPR0 ", "SPI Clock Rate Select" },
  { M6811_SPR0, "SPR0 ", "SPI Clock Rate Select" },
  { 0,  0, 0 }
  { 0,  0, 0 }
};
};
 
 
 
 
/* Flags of the SPSR register.  */
/* Flags of the SPSR register.  */
io_reg_desc spsr_desc[] = {
io_reg_desc spsr_desc[] = {
  { M6811_SPIF, "SPIF ", "SPI Transfer Complete flag" },
  { M6811_SPIF, "SPIF ", "SPI Transfer Complete flag" },
  { M6811_WCOL, "WCOL ", "Write Collision" },
  { M6811_WCOL, "WCOL ", "Write Collision" },
  { M6811_MODF, "MODF ", "Mode Fault" },
  { M6811_MODF, "MODF ", "Mode Fault" },
  { 0,  0, 0 }
  { 0,  0, 0 }
};
};
 
 
static void
static void
m68hc11spi_info (struct hw *me)
m68hc11spi_info (struct hw *me)
{
{
  SIM_DESC sd;
  SIM_DESC sd;
  uint16 base = 0;
  uint16 base = 0;
  sim_cpu *cpu;
  sim_cpu *cpu;
  struct m68hc11spi *controller;
  struct m68hc11spi *controller;
  uint8 val;
  uint8 val;
 
 
  sd = hw_system (me);
  sd = hw_system (me);
  cpu = STATE_CPU (sd, 0);
  cpu = STATE_CPU (sd, 0);
  controller = hw_data (me);
  controller = hw_data (me);
 
 
  sim_io_printf (sd, "M68HC11 SPI:\n");
  sim_io_printf (sd, "M68HC11 SPI:\n");
 
 
  base = cpu_get_io_base (cpu);
  base = cpu_get_io_base (cpu);
 
 
  val = cpu->ios[M6811_SPCR];
  val = cpu->ios[M6811_SPCR];
  print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR);
  print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR);
  sim_io_printf (sd, "\n");
  sim_io_printf (sd, "\n");
 
 
  val = cpu->ios[M6811_SPSR];
  val = cpu->ios[M6811_SPSR];
  print_io_byte (sd, "SPSR", spsr_desc, val, base + M6811_SPSR);
  print_io_byte (sd, "SPSR", spsr_desc, val, base + M6811_SPSR);
  sim_io_printf (sd, "\n");
  sim_io_printf (sd, "\n");
 
 
  if (controller->spi_event)
  if (controller->spi_event)
    {
    {
      signed64 t;
      signed64 t;
 
 
      sim_io_printf (sd, "  SPI has %d bits to send\n",
      sim_io_printf (sd, "  SPI has %d bits to send\n",
                     controller->tx_bit + 1);
                     controller->tx_bit + 1);
      t = hw_event_remain_time (me, controller->spi_event);
      t = hw_event_remain_time (me, controller->spi_event);
      sim_io_printf (sd, "  SPI current bit-cycle finished in %s\n",
      sim_io_printf (sd, "  SPI current bit-cycle finished in %s\n",
                     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
                     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
 
 
      t += (controller->tx_bit + 1) * 2 * controller->clock;
      t += (controller->tx_bit + 1) * 2 * controller->clock;
      sim_io_printf (sd, "  SPI operation finished in %s\n",
      sim_io_printf (sd, "  SPI operation finished in %s\n",
                     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
                     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
    }
    }
}
}
 
 
static int
static int
m68hc11spi_ioctl (struct hw *me,
m68hc11spi_ioctl (struct hw *me,
                  hw_ioctl_request request,
                  hw_ioctl_request request,
                  va_list ap)
                  va_list ap)
{
{
  m68hc11spi_info (me);
  m68hc11spi_info (me);
  return 0;
  return 0;
}
}
 
 
/* generic read/write */
/* generic read/write */
 
 
static unsigned
static unsigned
m68hc11spi_io_read_buffer (struct hw *me,
m68hc11spi_io_read_buffer (struct hw *me,
                           void *dest,
                           void *dest,
                           int space,
                           int space,
                           unsigned_word base,
                           unsigned_word base,
                           unsigned nr_bytes)
                           unsigned nr_bytes)
{
{
  SIM_DESC sd;
  SIM_DESC sd;
  struct m68hc11spi *controller;
  struct m68hc11spi *controller;
  sim_cpu *cpu;
  sim_cpu *cpu;
  unsigned8 val;
  unsigned8 val;
 
 
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
 
 
  sd  = hw_system (me);
  sd  = hw_system (me);
  cpu = STATE_CPU (sd, 0);
  cpu = STATE_CPU (sd, 0);
  controller = hw_data (me);
  controller = hw_data (me);
 
 
  switch (base)
  switch (base)
    {
    {
    case M6811_SPSR:
    case M6811_SPSR:
      controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
      controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
        & (M6811_SPIF | M6811_WCOL | M6811_MODF);
        & (M6811_SPIF | M6811_WCOL | M6811_MODF);
 
 
    case M6811_SPCR:
    case M6811_SPCR:
      val = cpu->ios[base];
      val = cpu->ios[base];
      break;
      break;
 
 
    case M6811_SPDR:
    case M6811_SPDR:
      if (controller->rx_clear_scsr)
      if (controller->rx_clear_scsr)
        {
        {
          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
          controller->rx_clear_scsr = 0;
          controller->rx_clear_scsr = 0;
          interrupts_update_pending (&cpu->cpu_interrupts);
          interrupts_update_pending (&cpu->cpu_interrupts);
        }
        }
      val = controller->rx_char;
      val = controller->rx_char;
      break;
      break;
 
 
    default:
    default:
      return 0;
      return 0;
    }
    }
  *((unsigned8*) dest) = val;
  *((unsigned8*) dest) = val;
  return 1;
  return 1;
}
}
 
 
static unsigned
static unsigned
m68hc11spi_io_write_buffer (struct hw *me,
m68hc11spi_io_write_buffer (struct hw *me,
                            const void *source,
                            const void *source,
                            int space,
                            int space,
                            unsigned_word base,
                            unsigned_word base,
                            unsigned nr_bytes)
                            unsigned nr_bytes)
{
{
  SIM_DESC sd;
  SIM_DESC sd;
  struct m68hc11spi *controller;
  struct m68hc11spi *controller;
  sim_cpu *cpu;
  sim_cpu *cpu;
  unsigned8 val;
  unsigned8 val;
 
 
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
 
 
  sd  = hw_system (me);
  sd  = hw_system (me);
  cpu = STATE_CPU (sd, 0);
  cpu = STATE_CPU (sd, 0);
  controller = hw_data (me);
  controller = hw_data (me);
 
 
  val = *((const unsigned8*) source);
  val = *((const unsigned8*) source);
  switch (base)
  switch (base)
    {
    {
    case M6811_SPCR:
    case M6811_SPCR:
      cpu->ios[M6811_SPCR] = val;
      cpu->ios[M6811_SPCR] = val;
 
 
      /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock.
      /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock.
         We have to drive the clock pin and need a 2x faster clock.  */
         We have to drive the clock pin and need a 2x faster clock.  */
      switch (val & (M6811_SPR1 | M6811_SPR0))
      switch (val & (M6811_SPR1 | M6811_SPR0))
        {
        {
        case 0:
        case 0:
          controller->clock = 1;
          controller->clock = 1;
          break;
          break;
 
 
        case 1:
        case 1:
          controller->clock = 2;
          controller->clock = 2;
          break;
          break;
 
 
        case 2:
        case 2:
          controller->clock = 8;
          controller->clock = 8;
          break;
          break;
 
 
        default:
        default:
          controller->clock = 16;
          controller->clock = 16;
          break;
          break;
        }
        }
 
 
      /* Set the clock pin.  */
      /* Set the clock pin.  */
      if ((val & M6811_CPOL)
      if ((val & M6811_CPOL)
          && (controller->spi_event == 0
          && (controller->spi_event == 0
              || ((val & M6811_CPHA) && controller->mode == 1)))
              || ((val & M6811_CPHA) && controller->mode == 1)))
        controller->clk_pin = 1;
        controller->clk_pin = 1;
      else
      else
        controller->clk_pin = 0;
        controller->clk_pin = 0;
 
 
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
      break;
      break;
 
 
      /* Can't write to SPSR.  */
      /* Can't write to SPSR.  */
    case M6811_SPSR:
    case M6811_SPSR:
      break;
      break;
 
 
    case M6811_SPDR:
    case M6811_SPDR:
      if (!(cpu->ios[M6811_SPCR] & M6811_SPE))
      if (!(cpu->ios[M6811_SPCR] & M6811_SPE))
        {
        {
          return 0;
          return 0;
        }
        }
 
 
      if (controller->rx_clear_scsr)
      if (controller->rx_clear_scsr)
        {
        {
          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
          controller->rx_clear_scsr = 0;
          controller->rx_clear_scsr = 0;
          interrupts_update_pending (&cpu->cpu_interrupts);
          interrupts_update_pending (&cpu->cpu_interrupts);
        }
        }
 
 
      /* If transfer is taking place, a write to SPDR
      /* If transfer is taking place, a write to SPDR
         generates a collision.  */
         generates a collision.  */
      if (controller->spi_event)
      if (controller->spi_event)
        {
        {
          cpu->ios[M6811_SPSR] |= M6811_WCOL;
          cpu->ios[M6811_SPSR] |= M6811_WCOL;
          break;
          break;
        }
        }
 
 
      /* Refuse the write if there was no read of SPSR.  */
      /* Refuse the write if there was no read of SPSR.  */
      /* ???? TBD. */
      /* ???? TBD. */
 
 
      /* Prepare to send a byte.  */
      /* Prepare to send a byte.  */
      controller->tx_char = val;
      controller->tx_char = val;
      controller->mode   = SPI_START_BYTE;
      controller->mode   = SPI_START_BYTE;
 
 
      /* Toggle clock pin internal value when CPHA is 0 so that
      /* Toggle clock pin internal value when CPHA is 0 so that
         it will really change in the middle of a bit.  */
         it will really change in the middle of a bit.  */
      if (!(cpu->ios[M6811_SPCR] & M6811_CPHA))
      if (!(cpu->ios[M6811_SPCR] & M6811_CPHA))
        controller->clk_pin = ~controller->clk_pin;
        controller->clk_pin = ~controller->clk_pin;
 
 
      cpu->ios[M6811_SPDR] = val;
      cpu->ios[M6811_SPDR] = val;
 
 
      /* Activate transmission.  */
      /* Activate transmission.  */
      m68hc11spi_clock (me, NULL);
      m68hc11spi_clock (me, NULL);
      break;
      break;
 
 
    default:
    default:
      return 0;
      return 0;
    }
    }
  return nr_bytes;
  return nr_bytes;
}
}
 
 
 
 
const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
  { "m68hc11spi", m68hc11spi_finish },
  { "m68hc11spi", m68hc11spi_finish },
  { "m68hc12spi", m68hc11spi_finish },
  { "m68hc12spi", m68hc11spi_finish },
  { NULL },
  { NULL },
};
};
 
 
 
 

powered by: WebSVN 2.1.0

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