xref: /netbsd-src/external/gpl3/gdb/dist/sim/m68hc11/dv-m68hc11spi.c (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
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 
545