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