1 /* dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
2 Copyright (C) 2000-2023 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@nerim.fr)
4 (From a driver model Contributed by Cygnus Solutions.)
6 This file is part of the program GDB, the GNU debugger.
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.
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.
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/>.
23 /* This must come before any other includes. */
28 #include "dv-sockser.h"
29 #include "sim-assert.h"
31 #include "m68hc11-sim.h"
35 m68hc11spi - m68hc11 SPI interface
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:
47 - Write collision detection
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.
74 static const struct hw_port_descriptor m68hc11spi_ports
[] =
76 { "reset", RESET_PORT
, 0, input_port
, },
84 /* Information about next character to be transmited. */
85 unsigned char tx_char
;
89 unsigned char rx_char
;
90 unsigned char rx_clear_scsr
;
91 unsigned char clk_pin
;
93 /* SPI clock rate (twice the real clock). */
96 /* Periodic SPI event. */
97 struct hw_event
* spi_event
;
102 /* Finish off the partially created hw device. Attach our local
103 callbacks. Wire up our port names etc */
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
;
110 #define M6811_SPI_FIRST_REG (M6811_SPCR)
111 #define M6811_SPI_LAST_REG (M6811_SPDR)
115 attach_m68hc11spi_regs (struct hw
*me
,
116 struct m68hc11spi
*controller
)
118 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
, io_map
,
120 M6811_SPI_LAST_REG
- M6811_SPI_FIRST_REG
+ 1,
125 m68hc11spi_finish (struct hw
*me
)
127 struct m68hc11spi
*controller
;
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
);
136 set_hw_ioctl (me
, m68hc11spi_ioctl
);
138 me
->to_ioctl
= m68hc11spi_ioctl
;
141 /* Attach ourself to our parent bus. */
142 attach_m68hc11spi_regs (me
, controller
);
144 /* Initialize to reset state. */
145 controller
->spi_event
= NULL
;
146 controller
->rx_clear_scsr
= 0;
151 /* An event arrives on an interrupt port */
154 m68hc11spi_port_event (struct hw
*me
,
161 struct m68hc11spi
*controller
;
165 controller
= hw_data (me
);
167 cpu
= STATE_CPU (sd
, 0);
172 HW_TRACE ((me
, "SPI reset"));
174 /* Reset the state of SPI registers. */
175 controller
->rx_clear_scsr
= 0;
176 if (controller
->spi_event
)
178 hw_event_queue_deschedule (me
, controller
->spi_event
);
179 controller
->spi_event
= 0;
183 m68hc11spi_io_write_buffer (me
, &val
, io_map
,
184 (unsigned_word
) M6811_SPCR
, 1);
189 hw_abort (me
, "Event on unknown port %d", my_port
);
195 set_bit_port (struct hw
*me
, sim_cpu
*cpu
, int port
, int mask
, int value
)
197 struct m68hc11_sim_cpu
*m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
201 val
= m68hc11_cpu
->ios
[port
] | mask
;
203 val
= m68hc11_cpu
->ios
[port
] & ~mask
;
205 /* Set the new value and post an event to inform other devices
206 that pin 'port' changed. */
207 m68hc11cpu_set_port (me
, cpu
, port
, val
);
211 /* When a character is sent/received by the SPI, the PD2..PD5 line
212 are driven by the following signals:
215 -----+---------+--------+---/-+-------
217 MISO +---------+--------+---/-+
219 CLK _______/ \____/ \__ CPOL=0, CPHA=0
221 \____/ \___/ CPOL=1, CPHA=0
223 __/ \____/ \___/ CPOL=0, CPHA=1
225 \____/ \____/ \__ CPOL=1, CPHA=1
228 \__________________________//___/
237 #define SPI_START_BYTE 0
238 #define SPI_START_BIT 1
239 #define SPI_MIDDLE_BIT 2
242 m68hc11spi_clock (struct hw
*me
, void *data
)
245 struct m68hc11spi
* controller
;
247 struct m68hc11_sim_cpu
*m68hc11_cpu
;
248 int check_interrupt
= 0;
250 controller
= hw_data (me
);
252 cpu
= STATE_CPU (sd
, 0);
253 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
255 /* Cleanup current event. */
256 if (controller
->spi_event
)
258 hw_event_queue_deschedule (me
, controller
->spi_event
);
259 controller
->spi_event
= 0;
262 /* Change a bit of data at each two SPI event. */
263 if (controller
->mode
== SPI_START_BIT
)
265 /* Reflect the bit value on bit 2 of port D. */
266 set_bit_port (me
, cpu
, M6811_PORTD
, (1 << 2),
267 (controller
->tx_char
& (1 << controller
->tx_bit
)));
268 controller
->tx_bit
--;
269 controller
->mode
= SPI_MIDDLE_BIT
;
271 else if (controller
->mode
== SPI_MIDDLE_BIT
)
273 controller
->mode
= SPI_START_BIT
;
276 if (controller
->mode
== SPI_START_BYTE
)
278 /* Start a new SPI transfer. */
280 /* TBD: clear SS output. */
281 controller
->mode
= SPI_START_BIT
;
282 controller
->tx_bit
= 7;
283 set_bit_port (me
, cpu
, M6811_PORTD
, (1 << 4), ~controller
->clk_pin
);
287 /* Change the SPI clock at each event on bit 4 of port D. */
288 controller
->clk_pin
= ~controller
->clk_pin
;
289 set_bit_port (me
, cpu
, M6811_PORTD
, (1 << 4), controller
->clk_pin
);
292 /* Transmit is now complete for this byte. */
293 if (controller
->mode
== SPI_START_BIT
&& controller
->tx_bit
< 0)
295 controller
->rx_clear_scsr
= 0;
296 m68hc11_cpu
->ios
[M6811_SPSR
] |= M6811_SPIF
;
297 if (m68hc11_cpu
->ios
[M6811_SPCR
] & M6811_SPIE
)
302 controller
->spi_event
= hw_event_queue_schedule (me
, controller
->clock
,
308 interrupts_update_pending (&m68hc11_cpu
->cpu_interrupts
);
311 /* Flags of the SPCR register. */
312 io_reg_desc spcr_desc
[] = {
313 { M6811_SPIE
, "SPIE ", "Serial Peripheral Interrupt Enable" },
314 { M6811_SPE
, "SPE ", "Serial Peripheral System Enable" },
315 { M6811_DWOM
, "DWOM ", "Port D Wire-OR mode option" },
316 { M6811_MSTR
, "MSTR ", "Master Mode Select" },
317 { M6811_CPOL
, "CPOL ", "Clock Polarity" },
318 { M6811_CPHA
, "CPHA ", "Clock Phase" },
319 { M6811_SPR1
, "SPR1 ", "SPI Clock Rate Select" },
320 { M6811_SPR0
, "SPR0 ", "SPI Clock Rate Select" },
325 /* Flags of the SPSR register. */
326 io_reg_desc spsr_desc
[] = {
327 { M6811_SPIF
, "SPIF ", "SPI Transfer Complete flag" },
328 { M6811_WCOL
, "WCOL ", "Write Collision" },
329 { M6811_MODF
, "MODF ", "Mode Fault" },
334 m68hc11spi_info (struct hw
*me
)
339 struct m68hc11_sim_cpu
*m68hc11_cpu
;
340 struct m68hc11spi
*controller
;
344 cpu
= STATE_CPU (sd
, 0);
345 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
346 controller
= hw_data (me
);
348 sim_io_printf (sd
, "M68HC11 SPI:\n");
350 base
= cpu_get_io_base (cpu
);
352 val
= m68hc11_cpu
->ios
[M6811_SPCR
];
353 print_io_byte (sd
, "SPCR", spcr_desc
, val
, base
+ M6811_SPCR
);
354 sim_io_printf (sd
, "\n");
356 val
= m68hc11_cpu
->ios
[M6811_SPSR
];
357 print_io_byte (sd
, "SPSR", spsr_desc
, val
, base
+ M6811_SPSR
);
358 sim_io_printf (sd
, "\n");
360 if (controller
->spi_event
)
364 sim_io_printf (sd
, " SPI has %d bits to send\n",
365 controller
->tx_bit
+ 1);
366 t
= hw_event_remain_time (me
, controller
->spi_event
);
367 sim_io_printf (sd
, " SPI current bit-cycle finished in %s\n",
368 cycle_to_string (cpu
, t
, PRINT_TIME
| PRINT_CYCLE
));
370 t
+= (controller
->tx_bit
+ 1) * 2 * controller
->clock
;
371 sim_io_printf (sd
, " SPI operation finished in %s\n",
372 cycle_to_string (cpu
, t
, PRINT_TIME
| PRINT_CYCLE
));
377 m68hc11spi_ioctl (struct hw
*me
,
378 hw_ioctl_request request
,
381 m68hc11spi_info (me
);
385 /* generic read/write */
388 m68hc11spi_io_read_buffer (struct hw
*me
,
395 struct m68hc11spi
*controller
;
397 struct m68hc11_sim_cpu
*m68hc11_cpu
;
400 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
403 cpu
= STATE_CPU (sd
, 0);
404 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
405 controller
= hw_data (me
);
410 controller
->rx_clear_scsr
= m68hc11_cpu
->ios
[M6811_SCSR
]
411 & (M6811_SPIF
| M6811_WCOL
| M6811_MODF
);
414 val
= m68hc11_cpu
->ios
[base
];
418 if (controller
->rx_clear_scsr
)
420 m68hc11_cpu
->ios
[M6811_SPSR
] &= ~controller
->rx_clear_scsr
;
421 controller
->rx_clear_scsr
= 0;
422 interrupts_update_pending (&m68hc11_cpu
->cpu_interrupts
);
424 val
= controller
->rx_char
;
430 *((uint8_t*) dest
) = val
;
435 m68hc11spi_io_write_buffer (struct hw
*me
,
442 struct m68hc11spi
*controller
;
444 struct m68hc11_sim_cpu
*m68hc11_cpu
;
447 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
450 cpu
= STATE_CPU (sd
, 0);
451 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
452 controller
= hw_data (me
);
454 val
= *((const uint8_t*) source
);
458 m68hc11_cpu
->ios
[M6811_SPCR
] = val
;
460 /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock.
461 We have to drive the clock pin and need a 2x faster clock. */
462 switch (val
& (M6811_SPR1
| M6811_SPR0
))
465 controller
->clock
= 1;
469 controller
->clock
= 2;
473 controller
->clock
= 8;
477 controller
->clock
= 16;
481 /* Set the clock pin. */
482 if ((val
& M6811_CPOL
)
483 && (controller
->spi_event
== 0
484 || ((val
& M6811_CPHA
) && controller
->mode
== 1)))
485 controller
->clk_pin
= 1;
487 controller
->clk_pin
= 0;
489 set_bit_port (me
, cpu
, M6811_PORTD
, (1 << 4), controller
->clk_pin
);
492 /* Can't write to SPSR. */
497 if (!(m68hc11_cpu
->ios
[M6811_SPCR
] & M6811_SPE
))
502 if (controller
->rx_clear_scsr
)
504 m68hc11_cpu
->ios
[M6811_SPSR
] &= ~controller
->rx_clear_scsr
;
505 controller
->rx_clear_scsr
= 0;
506 interrupts_update_pending (&m68hc11_cpu
->cpu_interrupts
);
509 /* If transfer is taking place, a write to SPDR
510 generates a collision. */
511 if (controller
->spi_event
)
513 m68hc11_cpu
->ios
[M6811_SPSR
] |= M6811_WCOL
;
517 /* Refuse the write if there was no read of SPSR. */
520 /* Prepare to send a byte. */
521 controller
->tx_char
= val
;
522 controller
->mode
= SPI_START_BYTE
;
524 /* Toggle clock pin internal value when CPHA is 0 so that
525 it will really change in the middle of a bit. */
526 if (!(m68hc11_cpu
->ios
[M6811_SPCR
] & M6811_CPHA
))
527 controller
->clk_pin
= ~controller
->clk_pin
;
529 m68hc11_cpu
->ios
[M6811_SPDR
] = val
;
531 /* Activate transmission. */
532 m68hc11spi_clock (me
, NULL
);
542 const struct hw_descriptor dv_m68hc11spi_descriptor
[] = {
543 { "m68hc11spi", m68hc11spi_finish
},
544 { "m68hc12spi", m68hc11spi_finish
},