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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [sim/] [m68hc11/] [dv-m68hc11spi.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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