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