]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11spi.c
Preliminary support for 68HC12
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11spi.c
CommitLineData
e0709f50
AC
1/* 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
66enum
67{
68 RESET_PORT
69};
70
71
72static const struct hw_port_descriptor m68hc11spi_ports[] =
73{
74 { "reset", RESET_PORT, 0, input_port, },
75 { NULL, },
76};
77
78
79/* SPI */
80struct 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
103static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
104static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
105static hw_port_event_method m68hc11spi_port_event;
106static hw_ioctl_method m68hc11spi_ioctl;
107
108#define M6811_SPI_FIRST_REG (M6811_SPCR)
109#define M6811_SPI_LAST_REG (M6811_SPDR)
110
111
112static void
113attach_m68hc11spi_regs (struct hw *me,
114 struct m68hc11spi *controller)
115{
63348d04 116 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
e0709f50
AC
117 M6811_SPI_FIRST_REG,
118 M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
119 me);
120}
121
122static void
123m68hc11spi_finish (struct hw *me)
124{
125 struct m68hc11spi *controller;
126
127 controller = HW_ZALLOC (me, struct m68hc11spi);
e0709f50
AC
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
151static void
152m68hc11spi_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
192static void
193set_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
4d72d17a
SC
232#define SPI_START_BYTE 0
233#define SPI_START_BIT 1
234#define SPI_MIDDLE_BIT 2
e0709f50
AC
235
236void
237m68hc11spi_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 }
4d72d17a 264 else if (controller->mode == SPI_MIDDLE_BIT)
e0709f50
AC
265 {
266 controller->mode = SPI_START_BIT;
267 }
268
4d72d17a
SC
269 if (controller->mode == SPI_START_BYTE)
270 {
271 /* Start a new SPI transfer. */
e0709f50 272
4d72d17a
SC
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
e0709f50
AC
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. */
305io_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. */
319io_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
326static void
327m68hc11spi_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
4d72d17a
SC
355 sim_io_printf (sd, " SPI has %d bits to send\n",
356 controller->tx_bit + 1);
e0709f50 357 t = hw_event_remain_time (me, controller->spi_event);
2990a9f4
SC
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));
e0709f50
AC
364 }
365}
366
367static int
368m68hc11spi_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
378static unsigned
379m68hc11spi_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;
4d72d17a 411 interrupts_update_pending (&cpu->cpu_interrupts);
e0709f50
AC
412 }
413 val = controller->rx_char;
414 break;
415
416 default:
417 return 0;
418 }
419 *((unsigned8*) dest) = val;
420 return 1;
421}
422
423static unsigned
424m68hc11spi_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
4d72d17a
SC
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
e0709f50
AC
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;
4d72d17a 509 controller->mode = SPI_START_BYTE;
e0709f50
AC
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
529const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
b93775f5
SC
530 { "m68hc11spi", m68hc11spi_finish },
531 { "m68hc12spi", m68hc11spi_finish },
e0709f50
AC
532 { NULL },
533};
534