]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/m68hc11/dv-m68hc11spi.c
[gdb/testsuite] Fix timeout in gdb.tui/resize-2.exp
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11spi.c
1 /* dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
2 Copyright (C) 2000-2024 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 /* This must come before any other includes. */
24 #include "defs.h"
25
26 #include "sim-main.h"
27 #include "hw-main.h"
28 #include "dv-sockser.h"
29 #include "sim-assert.h"
30
31 #include "m68hc11-sim.h"
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
68 enum
69 {
70 RESET_PORT
71 };
72
73
74 static const struct hw_port_descriptor m68hc11spi_ports[] =
75 {
76 { "reset", RESET_PORT, 0, input_port, },
77 { NULL, },
78 };
79
80
81 /* SPI */
82 struct 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
105 static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
106 static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
107 static hw_port_event_method m68hc11spi_port_event;
108 static hw_ioctl_method m68hc11spi_ioctl;
109
110 #define M6811_SPI_FIRST_REG (M6811_SPCR)
111 #define M6811_SPI_LAST_REG (M6811_SPDR)
112
113
114 static void
115 attach_m68hc11spi_regs (struct hw *me,
116 struct m68hc11spi *controller)
117 {
118 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
119 M6811_SPI_FIRST_REG,
120 M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
121 me);
122 }
123
124 static void
125 m68hc11spi_finish (struct hw *me)
126 {
127 struct m68hc11spi *controller;
128
129 controller = HW_ZALLOC (me, struct m68hc11spi);
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
153 static void
154 m68hc11spi_port_event (struct hw *me,
155 int my_port,
156 struct hw *source,
157 int source_port,
158 int level)
159 {
160 struct m68hc11spi *controller;
161 uint8_t val;
162
163 controller = hw_data (me);
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
190 static void
191 set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value)
192 {
193 struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
194 uint8_t val;
195
196 if (value)
197 val = m68hc11_cpu->ios[port] | mask;
198 else
199 val = m68hc11_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 static void
238 m68hc11spi_clock (struct hw *me, void *data)
239 {
240 SIM_DESC sd;
241 struct m68hc11spi* controller;
242 sim_cpu *cpu;
243 struct m68hc11_sim_cpu *m68hc11_cpu;
244 int check_interrupt = 0;
245
246 controller = hw_data (me);
247 sd = hw_system (me);
248 cpu = STATE_CPU (sd, 0);
249 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
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 }
267 else if (controller->mode == SPI_MIDDLE_BIT)
268 {
269 controller->mode = SPI_START_BIT;
270 }
271
272 if (controller->mode == SPI_START_BYTE)
273 {
274 /* Start a new SPI transfer. */
275
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
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;
292 m68hc11_cpu->ios[M6811_SPSR] |= M6811_SPIF;
293 if (m68hc11_cpu->ios[M6811_SPCR] & M6811_SPIE)
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)
304 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
305 }
306
307 /* Flags of the SPCR register. */
308 io_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. */
322 io_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
329 static void
330 m68hc11spi_info (struct hw *me)
331 {
332 SIM_DESC sd;
333 uint16_t base = 0;
334 sim_cpu *cpu;
335 struct m68hc11_sim_cpu *m68hc11_cpu;
336 struct m68hc11spi *controller;
337 uint8_t val;
338
339 sd = hw_system (me);
340 cpu = STATE_CPU (sd, 0);
341 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
342 controller = hw_data (me);
343
344 sim_io_printf (sd, "M68HC11 SPI:\n");
345
346 base = cpu_get_io_base (cpu);
347
348 val = m68hc11_cpu->ios[M6811_SPCR];
349 print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR);
350 sim_io_printf (sd, "\n");
351
352 val = m68hc11_cpu->ios[M6811_SPSR];
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 {
358 int64_t t;
359
360 sim_io_printf (sd, " SPI has %d bits to send\n",
361 controller->tx_bit + 1);
362 t = hw_event_remain_time (me, controller->spi_event);
363 sim_io_printf (sd, " SPI current bit-cycle finished in %s\n",
364 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
365
366 t += (controller->tx_bit + 1) * 2 * controller->clock;
367 sim_io_printf (sd, " SPI operation finished in %s\n",
368 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
369 }
370 }
371
372 static int
373 m68hc11spi_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
383 static unsigned
384 m68hc11spi_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;
393 struct m68hc11_sim_cpu *m68hc11_cpu;
394 uint8_t val;
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);
400 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
401 controller = hw_data (me);
402
403 switch (base)
404 {
405 case M6811_SPSR:
406 controller->rx_clear_scsr = m68hc11_cpu->ios[M6811_SCSR]
407 & (M6811_SPIF | M6811_WCOL | M6811_MODF);
408 ATTRIBUTE_FALLTHROUGH;
409
410 case M6811_SPCR:
411 val = m68hc11_cpu->ios[base];
412 break;
413
414 case M6811_SPDR:
415 if (controller->rx_clear_scsr)
416 {
417 m68hc11_cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
418 controller->rx_clear_scsr = 0;
419 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
420 }
421 val = controller->rx_char;
422 break;
423
424 default:
425 return 0;
426 }
427 *((uint8_t*) dest) = val;
428 return 1;
429 }
430
431 static unsigned
432 m68hc11spi_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;
441 struct m68hc11_sim_cpu *m68hc11_cpu;
442 uint8_t val;
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);
448 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
449 controller = hw_data (me);
450
451 val = *((const uint8_t*) source);
452 switch (base)
453 {
454 case M6811_SPCR:
455 m68hc11_cpu->ios[M6811_SPCR] = val;
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:
494 if (!(m68hc11_cpu->ios[M6811_SPCR] & M6811_SPE))
495 {
496 return 0;
497 }
498
499 if (controller->rx_clear_scsr)
500 {
501 m68hc11_cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
502 controller->rx_clear_scsr = 0;
503 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
504 }
505
506 /* If transfer is taking place, a write to SPDR
507 generates a collision. */
508 if (controller->spi_event)
509 {
510 m68hc11_cpu->ios[M6811_SPSR] |= M6811_WCOL;
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;
519 controller->mode = SPI_START_BYTE;
520
521 /* Toggle clock pin internal value when CPHA is 0 so that
522 it will really change in the middle of a bit. */
523 if (!(m68hc11_cpu->ios[M6811_SPCR] & M6811_CPHA))
524 controller->clk_pin = ~controller->clk_pin;
525
526 m68hc11_cpu->ios[M6811_SPDR] = val;
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
539 const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
540 { "m68hc11spi", m68hc11spi_finish },
541 { "m68hc12spi", m68hc11spi_finish },
542 { NULL },
543 };
544