]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11spi.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11spi.c
CommitLineData
e0709f50 1/* dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
8acc9f48 2 Copyright (C) 2000-2013 Free Software Foundation, Inc.
a685700c 3 Written by Stephane Carrez (stcarrez@nerim.fr)
e0709f50
AC
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
4744ac1b 10 the Free Software Foundation; either version 3 of the License, or
e0709f50 11 (at your option) any later version.
4744ac1b 12
e0709f50
AC
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.
4744ac1b 17
e0709f50 18 You should have received a copy of the GNU General Public License
4744ac1b 19 along with this program. If not, see <http://www.gnu.org/licenses/>.
e0709f50
AC
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
65enum
66{
67 RESET_PORT
68};
69
70
71static const struct hw_port_descriptor m68hc11spi_ports[] =
72{
73 { "reset", RESET_PORT, 0, input_port, },
74 { NULL, },
75};
76
77
78/* SPI */
79struct 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
102static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
103static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
104static hw_port_event_method m68hc11spi_port_event;
105static hw_ioctl_method m68hc11spi_ioctl;
106
107#define M6811_SPI_FIRST_REG (M6811_SPCR)
108#define M6811_SPI_LAST_REG (M6811_SPDR)
109
110
111static void
112attach_m68hc11spi_regs (struct hw *me,
113 struct m68hc11spi *controller)
114{
63348d04 115 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
e0709f50
AC
116 M6811_SPI_FIRST_REG,
117 M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
118 me);
119}
120
121static void
122m68hc11spi_finish (struct hw *me)
123{
124 struct m68hc11spi *controller;
125
126 controller = HW_ZALLOC (me, struct m68hc11spi);
e0709f50
AC
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
150static void
151m68hc11spi_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
191static void
192set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value)
193{
827ec39a
SC
194 uint8 val;
195
e0709f50 196 if (value)
827ec39a 197 val = cpu->ios[port] | mask;
e0709f50 198 else
827ec39a
SC
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);
e0709f50
AC
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
4d72d17a
SC
233#define SPI_START_BYTE 0
234#define SPI_START_BIT 1
235#define SPI_MIDDLE_BIT 2
e0709f50
AC
236
237void
238m68hc11spi_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 }
4d72d17a 265 else if (controller->mode == SPI_MIDDLE_BIT)
e0709f50
AC
266 {
267 controller->mode = SPI_START_BIT;
268 }
269
4d72d17a
SC
270 if (controller->mode == SPI_START_BYTE)
271 {
272 /* Start a new SPI transfer. */
e0709f50 273
4d72d17a
SC
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
e0709f50
AC
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. */
306io_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. */
320io_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
327static void
328m68hc11spi_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
4d72d17a
SC
356 sim_io_printf (sd, " SPI has %d bits to send\n",
357 controller->tx_bit + 1);
e0709f50 358 t = hw_event_remain_time (me, controller->spi_event);
2990a9f4 359 sim_io_printf (sd, " SPI current bit-cycle finished in %s\n",
a685700c 360 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
2990a9f4
SC
361
362 t += (controller->tx_bit + 1) * 2 * controller->clock;
363 sim_io_printf (sd, " SPI operation finished in %s\n",
a685700c 364 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
e0709f50
AC
365 }
366}
367
368static int
369m68hc11spi_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
379static unsigned
380m68hc11spi_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;
4d72d17a 412 interrupts_update_pending (&cpu->cpu_interrupts);
e0709f50
AC
413 }
414 val = controller->rx_char;
415 break;
416
417 default:
418 return 0;
419 }
420 *((unsigned8*) dest) = val;
421 return 1;
422}
423
424static unsigned
425m68hc11spi_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
4d72d17a
SC
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
e0709f50
AC
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;
4d72d17a 510 controller->mode = SPI_START_BYTE;
e0709f50
AC
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
530const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
b93775f5
SC
531 { "m68hc11spi", m68hc11spi_finish },
532 { "m68hc12spi", m68hc11spi_finish },
e0709f50
AC
533 { NULL },
534};
535