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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [sim/] [m68hc11/] [dv-m68hc11spi.c] - Blame information for rev 233

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

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

powered by: WebSVN 2.1.0

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