Home | History | Annotate | Line # | Download | only in m68hc11
      1 /*  dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
      2     Copyright (C) 2000-2024 Free Software Foundation, Inc.
      3     Written by Stephane Carrez (stcarrez (at) nerim.fr)
      4     (From a driver model Contributed by Cygnus Solutions.)
      5 
      6     This file is part of the program GDB, the GNU debugger.
      7 
      8     This program is free software; you can redistribute it and/or modify
      9     it under the terms of the GNU General Public License as published by
     10     the Free Software Foundation; either version 3 of the License, or
     11     (at your option) any later version.
     12 
     13     This program is distributed in the hope that it will be useful,
     14     but WITHOUT ANY WARRANTY; without even the implied warranty of
     15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16     GNU General Public License for more details.
     17 
     18     You should have received a copy of the GNU General Public License
     19     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     20 
     21     */
     22 
     23 /* This must come before any other includes.  */
     24 #include "defs.h"
     25 
     26 #include "sim-main.h"
     27 #include "hw-main.h"
     28 #include "dv-sockser.h"
     29 #include "sim-assert.h"
     30 
     31 #include "m68hc11-sim.h"
     32 
     33 /* DEVICE
     34 
     35         m68hc11spi - m68hc11 SPI interface
     36 
     37 
     38    DESCRIPTION
     39 
     40         Implements the m68hc11 Synchronous Serial Peripheral Interface
     41         described in the m68hc11 user guide (Chapter 8 in pink book).
     42         The SPI I/O controller is directly connected to the CPU
     43         interrupt.  The simulator implements:
     44 
     45             - SPI clock emulation
     46             - Data transfer
     47             - Write collision detection
     48 
     49 
     50    PROPERTIES
     51 
     52         None
     53 
     54 
     55    PORTS
     56 
     57    reset (input)
     58 
     59         Reset port. This port is only used to simulate a reset of the SPI
     60         I/O controller. It should be connected to the RESET output of the cpu.
     61 
     62    */
     63 
     64 
     65 
     66 /* port ID's */
     67 
     68 enum
     69 {
     70   RESET_PORT
     71 };
     72 
     73 
     74 static const struct hw_port_descriptor m68hc11spi_ports[] =
     75 {
     76   { "reset", RESET_PORT, 0, input_port, },
     77   { NULL, },
     78 };
     79 
     80 
     81 /* SPI */
     82 struct m68hc11spi
     83 {
     84   /* Information about next character to be transmited.  */
     85   unsigned char tx_char;
     86   int           tx_bit;
     87   unsigned char mode;
     88 
     89   unsigned char rx_char;
     90   unsigned char rx_clear_scsr;
     91   unsigned char clk_pin;
     92 
     93   /* SPI clock rate (twice the real clock).  */
     94   unsigned int clock;
     95 
     96   /* Periodic SPI event.  */
     97   struct hw_event* spi_event;
     98 };
     99 
    100 
    101 
    102 /* Finish off the partially created hw device.  Attach our local
    103    callbacks.  Wire up our port names etc */
    104 
    105 static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
    106 static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
    107 static hw_port_event_method m68hc11spi_port_event;
    108 static hw_ioctl_method m68hc11spi_ioctl;
    109 
    110 #define M6811_SPI_FIRST_REG (M6811_SPCR)
    111 #define M6811_SPI_LAST_REG  (M6811_SPDR)
    112 
    113 
    114 static void
    115 attach_m68hc11spi_regs (struct hw *me,
    116                         struct m68hc11spi *controller)
    117 {
    118   hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
    119                      M6811_SPI_FIRST_REG,
    120                      M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
    121 		     me);
    122 }
    123 
    124 static void
    125 m68hc11spi_finish (struct hw *me)
    126 {
    127   struct m68hc11spi *controller;
    128 
    129   controller = HW_ZALLOC (me, struct m68hc11spi);
    130   set_hw_data (me, controller);
    131   set_hw_io_read_buffer (me, m68hc11spi_io_read_buffer);
    132   set_hw_io_write_buffer (me, m68hc11spi_io_write_buffer);
    133   set_hw_ports (me, m68hc11spi_ports);
    134   set_hw_port_event (me, m68hc11spi_port_event);
    135 #ifdef set_hw_ioctl
    136   set_hw_ioctl (me, m68hc11spi_ioctl);
    137 #else
    138   me->to_ioctl = m68hc11spi_ioctl;
    139 #endif
    140 
    141   /* Attach ourself to our parent bus.  */
    142   attach_m68hc11spi_regs (me, controller);
    143 
    144   /* Initialize to reset state.  */
    145   controller->spi_event = NULL;
    146   controller->rx_clear_scsr = 0;
    147 }
    148 
    149 
    150 
    151 /* An event arrives on an interrupt port */
    152 
    153 static void
    154 m68hc11spi_port_event (struct hw *me,
    155                        int my_port,
    156                        struct hw *source,
    157                        int source_port,
    158                        int level)
    159 {
    160   struct m68hc11spi *controller;
    161   uint8_t val;
    162 
    163   controller = hw_data (me);
    164   switch (my_port)
    165     {
    166     case RESET_PORT:
    167       {
    168 	HW_TRACE ((me, "SPI reset"));
    169 
    170         /* Reset the state of SPI registers.  */
    171         controller->rx_clear_scsr = 0;
    172         if (controller->spi_event)
    173           {
    174             hw_event_queue_deschedule (me, controller->spi_event);
    175             controller->spi_event = 0;
    176           }
    177 
    178         val = 0;
    179         m68hc11spi_io_write_buffer (me, &val, io_map,
    180                                     (unsigned_word) M6811_SPCR, 1);
    181         break;
    182       }
    183 
    184     default:
    185       hw_abort (me, "Event on unknown port %d", my_port);
    186       break;
    187     }
    188 }
    189 
    190 static void
    191 set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value)
    192 {
    193   struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
    194   uint8_t val;
    195 
    196   if (value)
    197     val = m68hc11_cpu->ios[port] | mask;
    198   else
    199     val = m68hc11_cpu->ios[port] & ~mask;
    200 
    201   /* Set the new value and post an event to inform other devices
    202      that pin 'port' changed.  */
    203   m68hc11cpu_set_port (me, cpu, port, val);
    204 }
    205 
    206 
    207 /* When a character is sent/received by the SPI, the PD2..PD5 line
    208    are driven by the following signals:
    209 
    210 	      B7	B6
    211       -----+---------+--------+---/-+-------
    212  MOSI      |    |    |   |    |     |
    213  MISO	   +---------+--------+---/-+
    214 		____      ___
    215  CLK	_______/    \____/   \__		CPOL=0, CPHA=0
    216 	_______	     ____     __
    217 	       \____/    \___/			CPOL=1, CPHA=0
    218 	   ____	     ____     __
    219 	__/    \____/    \___/			CPOL=0, CPHA=1
    220 	__	____      ___
    221 	  \____/    \____/   \__		CPOL=1, CPHA=1
    222 
    223  SS ___                                 ____
    224        \__________________________//___/
    225 
    226  MISO = PD2
    227  MOSI = PD3
    228  SCK  = PD4
    229  SS   = PD5
    230 
    231 */
    232 
    233 #define SPI_START_BYTE 0
    234 #define SPI_START_BIT  1
    235 #define SPI_MIDDLE_BIT 2
    236 
    237 static void
    238 m68hc11spi_clock (struct hw *me, void *data)
    239 {
    240   SIM_DESC sd;
    241   struct m68hc11spi* controller;
    242   sim_cpu *cpu;
    243   struct m68hc11_sim_cpu *m68hc11_cpu;
    244   int check_interrupt = 0;
    245 
    246   controller = hw_data (me);
    247   sd         = hw_system (me);
    248   cpu        = STATE_CPU (sd, 0);
    249   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
    250 
    251   /* Cleanup current event.  */
    252   if (controller->spi_event)
    253     {
    254       hw_event_queue_deschedule (me, controller->spi_event);
    255       controller->spi_event = 0;
    256     }
    257 
    258   /* Change a bit of data at each two SPI event.  */
    259   if (controller->mode == SPI_START_BIT)
    260     {
    261       /* Reflect the bit value on bit 2 of port D.  */
    262       set_bit_port (me, cpu, M6811_PORTD, (1 << 2),
    263                     (controller->tx_char & (1 << controller->tx_bit)));
    264       controller->tx_bit--;
    265       controller->mode = SPI_MIDDLE_BIT;
    266     }
    267   else if (controller->mode == SPI_MIDDLE_BIT)
    268     {
    269       controller->mode = SPI_START_BIT;
    270     }
    271 
    272   if (controller->mode == SPI_START_BYTE)
    273     {
    274       /* Start a new SPI transfer.  */
    275 
    276       /* TBD: clear SS output.  */
    277       controller->mode = SPI_START_BIT;
    278       controller->tx_bit = 7;
    279       set_bit_port (me, cpu, M6811_PORTD, (1 << 4), ~controller->clk_pin);
    280     }
    281   else
    282     {
    283       /* Change the SPI clock at each event on bit 4 of port D.  */
    284       controller->clk_pin = ~controller->clk_pin;
    285       set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
    286     }
    287 
    288   /* Transmit is now complete for this byte.  */
    289   if (controller->mode == SPI_START_BIT && controller->tx_bit < 0)
    290     {
    291       controller->rx_clear_scsr = 0;
    292       m68hc11_cpu->ios[M6811_SPSR] |= M6811_SPIF;
    293       if (m68hc11_cpu->ios[M6811_SPCR] & M6811_SPIE)
    294         check_interrupt = 1;
    295     }
    296   else
    297     {
    298       controller->spi_event = hw_event_queue_schedule (me, controller->clock,
    299                                                        m68hc11spi_clock,
    300                                                        NULL);
    301     }
    302 
    303   if (check_interrupt)
    304     interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
    305 }
    306 
    307 /* Flags of the SPCR register.  */
    308 io_reg_desc spcr_desc[] = {
    309   { M6811_SPIE, "SPIE ", "Serial Peripheral Interrupt Enable" },
    310   { M6811_SPE,  "SPE  ",  "Serial Peripheral System Enable" },
    311   { M6811_DWOM, "DWOM ", "Port D Wire-OR mode option" },
    312   { M6811_MSTR, "MSTR ", "Master Mode Select" },
    313   { M6811_CPOL, "CPOL ", "Clock Polarity" },
    314   { M6811_CPHA, "CPHA ", "Clock Phase" },
    315   { M6811_SPR1, "SPR1 ", "SPI Clock Rate Select" },
    316   { M6811_SPR0, "SPR0 ", "SPI Clock Rate Select" },
    317   { 0,  0, 0 }
    318 };
    319 
    320 
    321 /* Flags of the SPSR register.  */
    322 io_reg_desc spsr_desc[] = {
    323   { M6811_SPIF,	"SPIF ", "SPI Transfer Complete flag" },
    324   { M6811_WCOL, "WCOL ", "Write Collision" },
    325   { M6811_MODF, "MODF ", "Mode Fault" },
    326   { 0,  0, 0 }
    327 };
    328 
    329 static void
    330 m68hc11spi_info (struct hw *me)
    331 {
    332   SIM_DESC sd;
    333   uint16_t base = 0;
    334   sim_cpu *cpu;
    335   struct m68hc11_sim_cpu *m68hc11_cpu;
    336   struct m68hc11spi *controller;
    337   uint8_t val;
    338 
    339   sd = hw_system (me);
    340   cpu = STATE_CPU (sd, 0);
    341   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
    342   controller = hw_data (me);
    343 
    344   sim_io_printf (sd, "M68HC11 SPI:\n");
    345 
    346   base = cpu_get_io_base (cpu);
    347 
    348   val = m68hc11_cpu->ios[M6811_SPCR];
    349   print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR);
    350   sim_io_printf (sd, "\n");
    351 
    352   val = m68hc11_cpu->ios[M6811_SPSR];
    353   print_io_byte (sd, "SPSR", spsr_desc, val, base + M6811_SPSR);
    354   sim_io_printf (sd, "\n");
    355 
    356   if (controller->spi_event)
    357     {
    358       int64_t t;
    359 
    360       sim_io_printf (sd, "  SPI has %d bits to send\n",
    361                      controller->tx_bit + 1);
    362       t = hw_event_remain_time (me, controller->spi_event);
    363       sim_io_printf (sd, "  SPI current bit-cycle finished in %s\n",
    364 		     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
    365 
    366       t += (controller->tx_bit + 1) * 2 * controller->clock;
    367       sim_io_printf (sd, "  SPI operation finished in %s\n",
    368 		     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
    369     }
    370 }
    371 
    372 static int
    373 m68hc11spi_ioctl (struct hw *me,
    374                   hw_ioctl_request request,
    375                   va_list ap)
    376 {
    377   m68hc11spi_info (me);
    378   return 0;
    379 }
    380 
    381 /* generic read/write */
    382 
    383 static unsigned
    384 m68hc11spi_io_read_buffer (struct hw *me,
    385                            void *dest,
    386                            int space,
    387                            unsigned_word base,
    388                            unsigned nr_bytes)
    389 {
    390   SIM_DESC sd;
    391   struct m68hc11spi *controller;
    392   sim_cpu *cpu;
    393   struct m68hc11_sim_cpu *m68hc11_cpu;
    394   uint8_t val;
    395 
    396   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
    397 
    398   sd  = hw_system (me);
    399   cpu = STATE_CPU (sd, 0);
    400   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
    401   controller = hw_data (me);
    402 
    403   switch (base)
    404     {
    405     case M6811_SPSR:
    406       controller->rx_clear_scsr = m68hc11_cpu->ios[M6811_SCSR]
    407         & (M6811_SPIF | M6811_WCOL | M6811_MODF);
    408       ATTRIBUTE_FALLTHROUGH;
    409 
    410     case M6811_SPCR:
    411       val = m68hc11_cpu->ios[base];
    412       break;
    413 
    414     case M6811_SPDR:
    415       if (controller->rx_clear_scsr)
    416         {
    417           m68hc11_cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
    418           controller->rx_clear_scsr = 0;
    419           interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
    420         }
    421       val = controller->rx_char;
    422       break;
    423 
    424     default:
    425       return 0;
    426     }
    427   *((uint8_t*) dest) = val;
    428   return 1;
    429 }
    430 
    431 static unsigned
    432 m68hc11spi_io_write_buffer (struct hw *me,
    433                             const void *source,
    434                             int space,
    435                             unsigned_word base,
    436                             unsigned nr_bytes)
    437 {
    438   SIM_DESC sd;
    439   struct m68hc11spi *controller;
    440   sim_cpu *cpu;
    441   struct m68hc11_sim_cpu *m68hc11_cpu;
    442   uint8_t val;
    443 
    444   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
    445 
    446   sd  = hw_system (me);
    447   cpu = STATE_CPU (sd, 0);
    448   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
    449   controller = hw_data (me);
    450 
    451   val = *((const uint8_t*) source);
    452   switch (base)
    453     {
    454     case M6811_SPCR:
    455       m68hc11_cpu->ios[M6811_SPCR] = val;
    456 
    457       /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock.
    458          We have to drive the clock pin and need a 2x faster clock.  */
    459       switch (val & (M6811_SPR1 | M6811_SPR0))
    460         {
    461         case 0:
    462           controller->clock = 1;
    463           break;
    464 
    465         case 1:
    466           controller->clock = 2;
    467           break;
    468 
    469         case 2:
    470           controller->clock = 8;
    471           break;
    472 
    473         default:
    474           controller->clock = 16;
    475           break;
    476         }
    477 
    478       /* Set the clock pin.  */
    479       if ((val & M6811_CPOL)
    480           && (controller->spi_event == 0
    481               || ((val & M6811_CPHA) && controller->mode == 1)))
    482         controller->clk_pin = 1;
    483       else
    484         controller->clk_pin = 0;
    485 
    486       set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
    487       break;
    488 
    489       /* Can't write to SPSR.  */
    490     case M6811_SPSR:
    491       break;
    492 
    493     case M6811_SPDR:
    494       if (!(m68hc11_cpu->ios[M6811_SPCR] & M6811_SPE))
    495         {
    496           return 0;
    497         }
    498 
    499       if (controller->rx_clear_scsr)
    500         {
    501           m68hc11_cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
    502           controller->rx_clear_scsr = 0;
    503           interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
    504         }
    505 
    506       /* If transfer is taking place, a write to SPDR
    507          generates a collision.  */
    508       if (controller->spi_event)
    509         {
    510           m68hc11_cpu->ios[M6811_SPSR] |= M6811_WCOL;
    511           break;
    512         }
    513 
    514       /* Refuse the write if there was no read of SPSR.  */
    515       /* ???? TBD. */
    516 
    517       /* Prepare to send a byte.  */
    518       controller->tx_char = val;
    519       controller->mode   = SPI_START_BYTE;
    520 
    521       /* Toggle clock pin internal value when CPHA is 0 so that
    522          it will really change in the middle of a bit.  */
    523       if (!(m68hc11_cpu->ios[M6811_SPCR] & M6811_CPHA))
    524         controller->clk_pin = ~controller->clk_pin;
    525 
    526       m68hc11_cpu->ios[M6811_SPDR] = val;
    527 
    528       /* Activate transmission.  */
    529       m68hc11spi_clock (me, NULL);
    530       break;
    531 
    532     default:
    533       return 0;
    534     }
    535   return nr_bytes;
    536 }
    537 
    538 
    539 const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
    540   { "m68hc11spi", m68hc11spi_finish },
    541   { "m68hc12spi", m68hc11spi_finish },
    542   { NULL },
    543 };
    544 
    545