OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [m68hc11/] [dv-m68hc11.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*  dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2
    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
    Written by Stephane Carrez (stcarrez@worldnet.fr)
4
    (From a driver model Contributed by Cygnus Solutions.)
5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 
20
    */
21
 
22
 
23
#include "sim-main.h"
24
#include "hw-main.h"
25
 
26
/* DEVICE
27
 
28
        m68hc11cpu - m68hc11 cpu virtual device
29
        m68hc12cpu - m68hc12 cpu virtual device
30
 
31
   DESCRIPTION
32
 
33
        Implements the external m68hc11/68hc12 functionality.  This includes
34
        the delivery of of interrupts generated from other devices and the
35
        handling of device specific registers.
36
 
37
 
38
   PROPERTIES
39
 
40
   reg <base> <size>
41
 
42
        Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
43
 
44
   clock <hz>
45
 
46
        Frequency of the quartz used by the processor.
47
 
48
   mode [single | expanded | bootstrap | test]
49
 
50
        Cpu operating mode (the MODA and MODB external pins).
51
 
52
 
53
   PORTS
54
 
55
   reset (input)
56
 
57
        Reset the cpu and generates a cpu-reset event (used to reset
58
        other devices).
59
 
60
   nmi (input)
61
 
62
        Deliver a non-maskable interrupt to the processor.
63
 
64
 
65
   cpu-reset (output)
66
 
67
        Event generated after the CPU performs a reset.
68
 
69
 
70
   BUGS
71
 
72
        When delivering an interrupt, this code assumes that there is only
73
        one processor (number 0).
74
 
75
   */
76
 
77
 
78
 
79
struct m68hc11cpu {
80
  /* Pending interrupts for delivery by event handler.  */
81
  int              pending_reset;
82
  int              pending_nmi;
83
  int              pending_level;
84
  struct hw_event  *event;
85
  unsigned_word    attach_address;
86
  int              attach_size;
87
  int              attach_space;
88
};
89
 
90
 
91
 
92
/* input port ID's */
93
 
94
enum {
95
  RESET_PORT,
96
  NMI_PORT,
97
  IRQ_PORT,
98
  CPU_RESET_PORT
99
};
100
 
101
 
102
static const struct hw_port_descriptor m68hc11cpu_ports[] = {
103
 
104
  /* Interrupt inputs.  */
105
  { "reset",     RESET_PORT,     0, input_port, },
106
  { "nmi",       NMI_PORT,       0, input_port, },
107
  { "irq",       IRQ_PORT,       0, input_port, },
108
 
109
  /* Events generated for connection to other devices.  */
110
  { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
111
 
112
  { NULL, },
113
};
114
 
115
static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
116
static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
117
static hw_ioctl_method m68hc11_ioctl;
118
 
119
/* Finish off the partially created hw device.  Attach our local
120
   callbacks.  Wire up our port names etc.  */
121
 
122
static hw_port_event_method m68hc11cpu_port_event;
123
 
124
 
125
static void
126
dv_m6811_attach_address_callback (struct hw *me,
127
                                  int level,
128
                                  int space,
129
                                  address_word addr,
130
                                  address_word nr_bytes,
131
                                  struct hw *client)
132
{
133
  HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
134
             level, space, (unsigned long) addr, (unsigned long) nr_bytes,
135
             hw_path (client)));
136
 
137
  if (space != io_map)
138
    {
139
      sim_core_attach (hw_system (me),
140
                       NULL, /*cpu*/
141
                       level,
142
                       access_read_write_exec,
143
                       space, addr,
144
                       nr_bytes,
145
                       0, /* modulo */
146
                       client,
147
                       NULL);
148
    }
149
  else
150
    {
151
      /*printf("Attach from sub device: %d\n", (long) addr);*/
152
      sim_core_attach (hw_system (me),
153
                       NULL, /*cpu*/
154
                       level,
155
                       access_io,
156
                       space, addr,
157
                       nr_bytes,
158
                       0, /* modulo */
159
                       client,
160
                       NULL);
161
    }
162
}
163
 
164
static void
165
dv_m6811_detach_address_callback (struct hw *me,
166
                                  int level,
167
                                  int space,
168
                                  address_word addr,
169
                                  address_word nr_bytes,
170
                                  struct hw *client)
171
{
172
  sim_core_detach (hw_system (me), NULL, /*cpu*/
173
                   level, space, addr);
174
}
175
 
176
static void
177
m68hc11_delete (struct hw* me)
178
{
179
  struct m68hc11cpu *controller;
180
 
181
  controller = hw_data (me);
182
 
183
  hw_detach_address (me, M6811_IO_LEVEL,
184
                     controller->attach_space,
185
                     controller->attach_address,
186
                     controller->attach_size, me);
187
}
188
 
189
 
190
static void
191
attach_m68hc11_regs (struct hw *me,
192
                     struct m68hc11cpu *controller)
193
{
194
  SIM_DESC sd;
195
  sim_cpu *cpu;
196
  reg_property_spec reg;
197
  const char *cpu_mode;
198
 
199
  if (hw_find_property (me, "reg") == NULL)
200
    hw_abort (me, "Missing \"reg\" property");
201
 
202
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
203
    hw_abort (me, "\"reg\" property must contain one addr/size entry");
204
 
205
  hw_unit_address_to_attach_address (hw_parent (me),
206
                                     &reg.address,
207
                                     &controller->attach_space,
208
                                     &controller->attach_address,
209
                                     me);
210
  hw_unit_size_to_attach_size (hw_parent (me),
211
                               &reg.size,
212
                               &controller->attach_size, me);
213
 
214
  hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
215
                     controller->attach_space,
216
                     controller->attach_address,
217
                     controller->attach_size,
218
                     me);
219
  set_hw_delete (me, m68hc11_delete);
220
 
221
  /* Get cpu frequency.  */
222
  sd = hw_system (me);
223
  cpu = STATE_CPU (sd, 0);
224
  if (hw_find_property (me, "clock") != NULL)
225
    {
226
      cpu->cpu_frequency = hw_find_integer_property (me, "clock");
227
    }
228
  else
229
    {
230
      cpu->cpu_frequency = 8*1000*1000;
231
    }
232
 
233
  cpu_mode = "expanded";
234
  if (hw_find_property (me, "mode") != NULL)
235
    cpu_mode = hw_find_string_property (me, "mode");
236
 
237
  if (strcmp (cpu_mode, "test") == 0)
238
    cpu->cpu_mode = M6811_MDA | M6811_SMOD;
239
  else if (strcmp (cpu_mode, "bootstrap") == 0)
240
    cpu->cpu_mode = M6811_SMOD;
241
  else if (strcmp (cpu_mode, "single") == 0)
242
    cpu->cpu_mode = 0;
243
  else
244
    cpu->cpu_mode = M6811_MDA;
245
}
246
 
247
static void
248
m68hc11cpu_finish (struct hw *me)
249
{
250
  struct m68hc11cpu *controller;
251
 
252
  controller = HW_ZALLOC (me, struct m68hc11cpu);
253
  set_hw_data (me, controller);
254
  set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
255
  set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
256
  set_hw_ports (me, m68hc11cpu_ports);
257
  set_hw_port_event (me, m68hc11cpu_port_event);
258
  set_hw_attach_address (me, dv_m6811_attach_address_callback);
259
  set_hw_detach_address (me, dv_m6811_detach_address_callback);
260
#ifdef set_hw_ioctl
261
  set_hw_ioctl (me, m68hc11_ioctl);
262
#else
263
  me->to_ioctl = m68hc11_ioctl;
264
#endif
265
 
266
  /* Initialize the pending interrupt flags.  */
267
  controller->pending_level = 0;
268
  controller->pending_reset = 0;
269
  controller->pending_nmi = 0;
270
  controller->event = NULL;
271
 
272
  attach_m68hc11_regs (me, controller);
273
}
274
 
275
/* An event arrives on an interrupt port.  */
276
 
277
static void
278
deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
279
{
280
}
281
 
282
 
283
static void
284
m68hc11cpu_port_event (struct hw *me,
285
                       int my_port,
286
                       struct hw *source,
287
                       int source_port,
288
                       int level)
289
{
290
  struct m68hc11cpu *controller = hw_data (me);
291
  SIM_DESC sd;
292
  sim_cpu* cpu;
293
 
294
  sd  = hw_system (me);
295
  cpu = STATE_CPU (sd, 0);
296
  switch (my_port)
297
    {
298
    case RESET_PORT:
299
      HW_TRACE ((me, "port-in reset"));
300
 
301
      /* The reset is made in 3 steps:
302
         - First, cleanup the current sim_cpu struct.
303
         - Reset the devices.
304
         - Restart the cpu for the reset (get the CPU mode from the
305
           CONFIG register that gets initialized by EEPROM device).  */
306
      cpu_reset (cpu);
307
      hw_port_event (me, CPU_RESET_PORT, 1);
308
      cpu_restart (cpu);
309
      break;
310
 
311
    case NMI_PORT:
312
      controller->pending_nmi = 1;
313
      HW_TRACE ((me, "port-in nmi"));
314
      break;
315
 
316
    case IRQ_PORT:
317
      /* level == 0 means that the interrupt was cleared.  */
318
      if(level == 0)
319
        controller->pending_level = -1; /* signal end of interrupt */
320
      else
321
        controller->pending_level = level;
322
      HW_TRACE ((me, "port-in level=%d", level));
323
      break;
324
 
325
    default:
326
      hw_abort (me, "bad switch");
327
      break;
328
    }
329
 
330
  /* Schedule an event to be delivered immediately after current
331
     instruction.  */
332
  if(controller->event != NULL)
333
    hw_event_queue_deschedule(me, controller->event);
334
  controller->event =
335
    hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
336
}
337
 
338
 
339
io_reg_desc config_desc[] = {
340
  { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
341
  { M6811_NOCOP, "NOCOP ", "COP System Disable" },
342
  { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
343
  { M6811_EEON,  "EEON  ", "Enable On-chip EEprom" },
344
  { 0,  0, 0 }
345
};
346
 
347
io_reg_desc hprio_desc[] = {
348
  { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
349
  { M6811_SMOD,  "SMOD  ", "Special Mode" },
350
  { M6811_MDA,   "MDA   ", "Mode Select A" },
351
  { M6811_IRV,   "IRV   ", "Internal Read Visibility" },
352
  { 0,  0, 0 }
353
};
354
 
355
io_reg_desc option_desc[] = {
356
  { M6811_ADPU,  "ADPU  ", "A/D Powerup" },
357
  { M6811_CSEL,  "CSEL  ", "A/D/EE Charge pump clock source select" },
358
  { M6811_IRQE,  "IRQE  ", "IRQ Edge/Level sensitive" },
359
  { M6811_DLY,   "DLY   ", "Stop exit turn on delay" },
360
  { M6811_CME,   "CME   ", "Clock Monitor Enable" },
361
  { M6811_CR1,   "CR1   ", "COP timer rate select (CR1)" },
362
  { M6811_CR0,   "CR0   ", "COP timer rate select (CR0)" },
363
  { 0,  0, 0 }
364
};
365
 
366
static void
367
m68hc11_info (struct hw *me)
368
{
369
  SIM_DESC sd;
370
  uint16 base = 0;
371
  sim_cpu *cpu;
372
  struct m68hc11sio *controller;
373
  uint8 val;
374
 
375
  sd = hw_system (me);
376
  cpu = STATE_CPU (sd, 0);
377
  controller = hw_data (me);
378
 
379
  base = cpu_get_io_base (cpu);
380
  sim_io_printf (sd, "M68HC11:\n");
381
 
382
  val = cpu->ios[M6811_HPRIO];
383
  print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
384
  sim_io_printf (sd, "\n");
385
 
386
  val = cpu->ios[M6811_CONFIG];
387
  print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
388
  sim_io_printf (sd, "\n");
389
 
390
  val = cpu->ios[M6811_OPTION];
391
  print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
392
  sim_io_printf (sd, "\n");
393
 
394
  val = cpu->ios[M6811_INIT];
395
  print_io_byte (sd, "INIT  ", 0, val, base + M6811_INIT);
396
  sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
397
                 (((uint16) (val & 0xF0)) << 8),
398
                 (((uint16) (val & 0x0F)) << 12));
399
 
400
 
401
  cpu_info (sd, cpu);
402
  interrupts_info (sd, &cpu->cpu_interrupts);
403
}
404
 
405
static int
406
m68hc11_ioctl (struct hw *me,
407
               hw_ioctl_request request,
408
               va_list ap)
409
{
410
  m68hc11_info (me);
411
  return 0;
412
}
413
 
414
/* generic read/write */
415
 
416
static unsigned
417
m68hc11cpu_io_read_buffer (struct hw *me,
418
                           void *dest,
419
                           int space,
420
                           unsigned_word base,
421
                           unsigned nr_bytes)
422
{
423
  SIM_DESC sd;
424
  struct m68hc11cpu *controller = hw_data (me);
425
  sim_cpu *cpu;
426
  unsigned byte = 0;
427
  int result;
428
 
429
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
430
 
431
  sd  = hw_system (me);
432
  cpu = STATE_CPU (sd, 0);
433
 
434
  /* Handle reads for the sub-devices.  */
435
  base -= controller->attach_address;
436
  result = sim_core_read_buffer (sd, cpu,
437
                                 io_map, dest, base, nr_bytes);
438
  if (result > 0)
439
    return result;
440
 
441
  while (nr_bytes)
442
    {
443
      if (base >= controller->attach_size)
444
        break;
445
 
446
      memcpy (dest, &cpu->ios[base], 1);
447
      dest++;
448
      base++;
449
      byte++;
450
      nr_bytes--;
451
    }
452
  return byte;
453
}
454
 
455
 
456
static void
457
m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
458
                     unsigned_word addr, uint8 val)
459
{
460
  switch (addr)
461
    {
462
    case M6811_PORTA:
463
      break;
464
 
465
    case M6811_PIOC:
466
      break;
467
 
468
    case M6811_PORTC:
469
      break;
470
 
471
    case M6811_PORTB:
472
      break;
473
 
474
    case M6811_PORTCL:
475
      break;
476
 
477
    case M6811_DDRC:
478
      break;
479
 
480
    case M6811_PORTD:
481
      break;
482
 
483
    case M6811_DDRD:
484
      break;
485
 
486
    case M6811_TMSK2:
487
 
488
      break;
489
 
490
      /* Change the RAM and I/O mapping.  */
491
    case M6811_INIT:
492
      {
493
        uint8 old_bank = cpu->ios[M6811_INIT];
494
 
495
        cpu->ios[M6811_INIT] = val;
496
 
497
        /* Update IO mapping.  Detach from the old address
498
           and attach to the new one.  */
499
        if ((old_bank & 0xF0) != (val & 0xF0))
500
          {
501
            struct m68hc11cpu *controller = hw_data (me);
502
 
503
            hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
504
                               controller->attach_space,
505
                               controller->attach_address,
506
                               controller->attach_size,
507
                               me);
508
            controller->attach_address = (val & 0x0F0) << 12;
509
            hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
510
                               controller->attach_space,
511
                               controller->attach_address,
512
                               controller->attach_size,
513
                               me);
514
          }
515
        if ((old_bank & 0x0F) != (val & 0x0F))
516
          {
517
            ;
518
          }
519
        return;
520
      }
521
 
522
    /* Writing the config is similar to programing the eeprom.
523
       The config register value is the last byte of the EEPROM.
524
       This last byte is not mapped in memory (that's why we have
525
       to add '1' to 'end_addr').  */
526
    case M6811_CONFIG:
527
      {
528
        return;
529
      }
530
 
531
 
532
      /* COP reset.  */
533
    case M6811_COPRST:
534
      if (val == 0xAA && cpu->ios[addr] == 0x55)
535
        {
536
          val = 0;
537
          /* COP reset here.  */
538
        }
539
      break;
540
 
541
    default:
542
      break;
543
 
544
    }
545
  cpu->ios[addr] = val;
546
}
547
 
548
static unsigned
549
m68hc11cpu_io_write_buffer (struct hw *me,
550
                            const void *source,
551
                            int space,
552
                            unsigned_word base,
553
                            unsigned nr_bytes)
554
{
555
  SIM_DESC sd;
556
  struct m68hc11cpu *controller = hw_data (me);
557
  unsigned byte;
558
  sim_cpu *cpu;
559
  int result;
560
 
561
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
562
 
563
  sd = hw_system (me);
564
  cpu = STATE_CPU (sd, 0);
565
  base -= controller->attach_address;
566
  result = sim_core_write_buffer (sd, cpu,
567
                                  io_map, source, base, nr_bytes);
568
  if (result > 0)
569
    return result;
570
 
571
  byte = 0;
572
  while (nr_bytes)
573
    {
574
      uint8 val;
575
      if (base >= controller->attach_size)
576
        break;
577
 
578
      val = *((uint8*) source);
579
      m68hc11cpu_io_write (me, cpu, base, val);
580
      source++;
581
      base++;
582
      byte++;
583
      nr_bytes--;
584
    }
585
  return byte;
586
}
587
 
588
const struct hw_descriptor dv_m68hc11_descriptor[] = {
589
  { "m68hc11", m68hc11cpu_finish },
590
  { "m68hc12", m68hc11cpu_finish },
591
  { NULL },
592
};
593
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.