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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [sim/] [m68hc11/] [dv-m68hc11spi.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*  dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
2
    Copyright (C) 2000 Free Software Foundation, Inc.
3
    Written by Stephane Carrez (stcarrez@worldnet.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 2 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, write to the Free Software
20
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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
  /* TODO: Post an event to inform other devices that pin 'port' changes.
196
     This has only a sense if we provide some device that is logically
197
     connected to these pin ports (SCLK and MOSI) and that handles
198
     the SPI protocol.  */
199
  if (value)
200
    cpu->ios[port] |= mask;
201
  else
202
    cpu->ios[port] &= ~mask;
203
}
204
 
205
 
206
/* When a character is sent/received by the SPI, the PD2..PD5 line
207
   are driven by the following signals:
208
 
209
              B7        B6
210
      -----+---------+--------+---/-+-------
211
 MOSI      |    |    |   |    |     |
212
 MISO      +---------+--------+---/-+
213
                ____      ___
214
 CLK    _______/    \____/   \__                CPOL=0, CPHA=0
215
        _______      ____     __
216
               \____/    \___/                  CPOL=1, CPHA=0
217
           ____      ____     __
218
        __/    \____/    \___/                  CPOL=0, CPHA=1
219
        __      ____      ___
220
          \____/    \____/   \__                CPOL=1, CPHA=1
221
 
222
 SS ___                                 ____
223
       \__________________________//___/
224
 
225
 MISO = PD2
226
 MOSI = PD3
227
 SCK  = PD4
228
 SS   = PD5
229
 
230
*/
231
 
232
#define SPI_START_BYTE 0
233
#define SPI_START_BIT  1
234
#define SPI_MIDDLE_BIT 2
235
 
236
void
237
m68hc11spi_clock (struct hw *me, void *data)
238
{
239
  SIM_DESC sd;
240
  struct m68hc11spi* controller;
241
  sim_cpu *cpu;
242
  int check_interrupt = 0;
243
 
244
  controller = hw_data (me);
245
  sd         = hw_system (me);
246
  cpu        = STATE_CPU (sd, 0);
247
 
248
  /* Cleanup current event.  */
249
  if (controller->spi_event)
250
    {
251
      hw_event_queue_deschedule (me, controller->spi_event);
252
      controller->spi_event = 0;
253
    }
254
 
255
  /* Change a bit of data at each two SPI event.  */
256
  if (controller->mode == SPI_START_BIT)
257
    {
258
      /* Reflect the bit value on bit 2 of port D.  */
259
      set_bit_port (me, cpu, M6811_PORTD, (1 << 2),
260
                    (controller->tx_char & (1 << controller->tx_bit)));
261
      controller->tx_bit--;
262
      controller->mode = SPI_MIDDLE_BIT;
263
    }
264
  else if (controller->mode == SPI_MIDDLE_BIT)
265
    {
266
      controller->mode = SPI_START_BIT;
267
    }
268
 
269
  if (controller->mode == SPI_START_BYTE)
270
    {
271
      /* Start a new SPI transfer.  */
272
 
273
      /* TBD: clear SS output.  */
274
      controller->mode = SPI_START_BIT;
275
      controller->tx_bit = 7;
276
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), ~controller->clk_pin);
277
    }
278
  else
279
    {
280
      /* Change the SPI clock at each event on bit 4 of port D.  */
281
      controller->clk_pin = ~controller->clk_pin;
282
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
283
    }
284
 
285
  /* Transmit is now complete for this byte.  */
286
  if (controller->mode == SPI_START_BIT && controller->tx_bit < 0)
287
    {
288
      controller->rx_clear_scsr = 0;
289
      cpu->ios[M6811_SPSR] |= M6811_SPIF;
290
      if (cpu->ios[M6811_SPCR] & M6811_SPIE)
291
        check_interrupt = 1;
292
    }
293
  else
294
    {
295
      controller->spi_event = hw_event_queue_schedule (me, controller->clock,
296
                                                       m68hc11spi_clock,
297
                                                       NULL);
298
    }
299
 
300
  if (check_interrupt)
301
    interrupts_update_pending (&cpu->cpu_interrupts);
302
}
303
 
304
/* Flags of the SPCR register.  */
305
io_reg_desc spcr_desc[] = {
306
  { M6811_SPIE, "SPIE ", "Serial Peripheral Interrupt Enable" },
307
  { M6811_SPE,  "SPE  ",  "Serial Peripheral System Enable" },
308
  { M6811_DWOM, "DWOM ", "Port D Wire-OR mode option" },
309
  { M6811_MSTR, "MSTR ", "Master Mode Select" },
310
  { M6811_CPOL, "CPOL ", "Clock Polarity" },
311
  { M6811_CPHA, "CPHA ", "Clock Phase" },
312
  { M6811_SPR1, "SPR1 ", "SPI Clock Rate Select" },
313
  { M6811_SPR0, "SPR0 ", "SPI Clock Rate Select" },
314
  { 0,  0, 0 }
315
};
316
 
317
 
318
/* Flags of the SPSR register.  */
319
io_reg_desc spsr_desc[] = {
320
  { M6811_SPIF, "SPIF ", "SPI Transfer Complete flag" },
321
  { M6811_WCOL, "WCOL ", "Write Collision" },
322
  { M6811_MODF, "MODF ", "Mode Fault" },
323
  { 0,  0, 0 }
324
};
325
 
326
static void
327
m68hc11spi_info (struct hw *me)
328
{
329
  SIM_DESC sd;
330
  uint16 base = 0;
331
  sim_cpu *cpu;
332
  struct m68hc11spi *controller;
333
  uint8 val;
334
 
335
  sd = hw_system (me);
336
  cpu = STATE_CPU (sd, 0);
337
  controller = hw_data (me);
338
 
339
  sim_io_printf (sd, "M68HC11 SPI:\n");
340
 
341
  base = cpu_get_io_base (cpu);
342
 
343
  val = cpu->ios[M6811_SPCR];
344
  print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR);
345
  sim_io_printf (sd, "\n");
346
 
347
  val = cpu->ios[M6811_SPSR];
348
  print_io_byte (sd, "SPSR", spsr_desc, val, base + M6811_SPSR);
349
  sim_io_printf (sd, "\n");
350
 
351
  if (controller->spi_event)
352
    {
353
      signed64 t;
354
 
355
      sim_io_printf (sd, "  SPI has %d bits to send\n",
356
                     controller->tx_bit + 1);
357
      t = hw_event_remain_time (me, controller->spi_event);
358
      sim_io_printf (sd, "  SPI current bit-cycle finished in %s\n",
359
                     cycle_to_string (cpu, t));
360
 
361
      t += (controller->tx_bit + 1) * 2 * controller->clock;
362
      sim_io_printf (sd, "  SPI operation finished in %s\n",
363
                     cycle_to_string (cpu, t));
364
    }
365
}
366
 
367
static int
368
m68hc11spi_ioctl (struct hw *me,
369
                  hw_ioctl_request request,
370
                  va_list ap)
371
{
372
  m68hc11spi_info (me);
373
  return 0;
374
}
375
 
376
/* generic read/write */
377
 
378
static unsigned
379
m68hc11spi_io_read_buffer (struct hw *me,
380
                           void *dest,
381
                           int space,
382
                           unsigned_word base,
383
                           unsigned nr_bytes)
384
{
385
  SIM_DESC sd;
386
  struct m68hc11spi *controller;
387
  sim_cpu *cpu;
388
  unsigned8 val;
389
 
390
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
391
 
392
  sd  = hw_system (me);
393
  cpu = STATE_CPU (sd, 0);
394
  controller = hw_data (me);
395
 
396
  switch (base)
397
    {
398
    case M6811_SPSR:
399
      controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
400
        & (M6811_SPIF | M6811_WCOL | M6811_MODF);
401
 
402
    case M6811_SPCR:
403
      val = cpu->ios[base];
404
      break;
405
 
406
    case M6811_SPDR:
407
      if (controller->rx_clear_scsr)
408
        {
409
          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
410
          controller->rx_clear_scsr = 0;
411
          interrupts_update_pending (&cpu->cpu_interrupts);
412
        }
413
      val = controller->rx_char;
414
      break;
415
 
416
    default:
417
      return 0;
418
    }
419
  *((unsigned8*) dest) = val;
420
  return 1;
421
}
422
 
423
static unsigned
424
m68hc11spi_io_write_buffer (struct hw *me,
425
                            const void *source,
426
                            int space,
427
                            unsigned_word base,
428
                            unsigned nr_bytes)
429
{
430
  SIM_DESC sd;
431
  struct m68hc11spi *controller;
432
  sim_cpu *cpu;
433
  unsigned8 val;
434
 
435
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
436
 
437
  sd  = hw_system (me);
438
  cpu = STATE_CPU (sd, 0);
439
  controller = hw_data (me);
440
 
441
  val = *((const unsigned8*) source);
442
  switch (base)
443
    {
444
    case M6811_SPCR:
445
      cpu->ios[M6811_SPCR] = val;
446
 
447
      /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock.
448
         We have to drive the clock pin and need a 2x faster clock.  */
449
      switch (val & (M6811_SPR1 | M6811_SPR0))
450
        {
451
        case 0:
452
          controller->clock = 1;
453
          break;
454
 
455
        case 1:
456
          controller->clock = 2;
457
          break;
458
 
459
        case 2:
460
          controller->clock = 8;
461
          break;
462
 
463
        default:
464
          controller->clock = 16;
465
          break;
466
        }
467
 
468
      /* Set the clock pin.  */
469
      if ((val & M6811_CPOL)
470
          && (controller->spi_event == 0
471
              || ((val & M6811_CPHA) && controller->mode == 1)))
472
        controller->clk_pin = 1;
473
      else
474
        controller->clk_pin = 0;
475
 
476
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
477
      break;
478
 
479
      /* Can't write to SPSR.  */
480
    case M6811_SPSR:
481
      break;
482
 
483
    case M6811_SPDR:
484
      if (!(cpu->ios[M6811_SPCR] & M6811_SPE))
485
        {
486
          return 0;
487
        }
488
 
489
      if (controller->rx_clear_scsr)
490
        {
491
          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
492
          controller->rx_clear_scsr = 0;
493
          interrupts_update_pending (&cpu->cpu_interrupts);
494
        }
495
 
496
      /* If transfer is taking place, a write to SPDR
497
         generates a collision.  */
498
      if (controller->spi_event)
499
        {
500
          cpu->ios[M6811_SPSR] |= M6811_WCOL;
501
          break;
502
        }
503
 
504
      /* Refuse the write if there was no read of SPSR.  */
505
      /* ???? TBD. */
506
 
507
      /* Prepare to send a byte.  */
508
      controller->tx_char = val;
509
      controller->mode   = SPI_START_BYTE;
510
 
511
      /* Toggle clock pin internal value when CPHA is 0 so that
512
         it will really change in the middle of a bit.  */
513
      if (!(cpu->ios[M6811_SPCR] & M6811_CPHA))
514
        controller->clk_pin = ~controller->clk_pin;
515
 
516
      cpu->ios[M6811_SPDR] = val;
517
 
518
      /* Activate transmission.  */
519
      m68hc11spi_clock (me, NULL);
520
      break;
521
 
522
    default:
523
      return 0;
524
    }
525
  return nr_bytes;
526
}
527
 
528
 
529
const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
530
  { "m68hc11spi", m68hc11spi_finish },
531
  { "m68hc12spi", m68hc11spi_finish },
532
  { NULL },
533
};
534
 

powered by: WebSVN 2.1.0

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