OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [sim/] [m68hc11/] [dv-m68hc11.c] - Blame information for rev 221

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 24 jeremybenn
/*  dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
2
    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2007, 2008
3
    Free Software Foundation, Inc.
4
    Written by Stephane Carrez (stcarrez@nerim.fr)
5
    (From a driver model Contributed by Cygnus Solutions.)
6
 
7
    This program is free software; you can redistribute it and/or modify
8
    it under the terms of the GNU General Public License as published by
9
    the Free Software Foundation; either version 3 of the License, or
10
    (at your option) any later version.
11
 
12
    This program is distributed in the hope that it will be useful,
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
    GNU General Public License for more details.
16
 
17
    You should have received a copy of the GNU General Public License
18
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 
20
    */
21
 
22
 
23
#include "sim-main.h"
24
#include "sim-hw.h"
25
#include "hw-main.h"
26
#include "sim-options.h"
27
#include "hw-base.h"
28
#include <limits.h>
29
 
30
/* DEVICE
31
 
32
        m68hc11cpu - m68hc11 cpu virtual device
33
        m68hc12cpu - m68hc12 cpu virtual device
34
 
35
   DESCRIPTION
36
 
37
        Implements the external m68hc11/68hc12 functionality.  This includes
38
        the delivery of of interrupts generated from other devices and the
39
        handling of device specific registers.
40
 
41
 
42
   PROPERTIES
43
 
44
   reg <base> <size>
45
 
46
        Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
47
 
48
   clock <hz>
49
 
50
        Frequency of the quartz used by the processor.
51
 
52
   mode [single | expanded | bootstrap | test]
53
 
54
        Cpu operating mode (the MODA and MODB external pins).
55
 
56
 
57
   PORTS
58
 
59
   reset (input)
60
 
61
        Reset the cpu and generates a cpu-reset event (used to reset
62
        other devices).
63
 
64
   nmi (input)
65
 
66
        Deliver a non-maskable interrupt to the processor.
67
 
68
 
69
   set-port-a (input)
70
   set-port-c (input)
71
   set-pord-d (input)
72
 
73
        Allow an external device to set the value of port A, C or D inputs.
74
 
75
 
76
   cpu-reset (output)
77
 
78
        Event generated after the CPU performs a reset.
79
 
80
 
81
   port-a (output)
82
   port-b (output)
83
   port-c (output)
84
   port-d (output)
85
 
86
        Event generated when the value of the output port A, B, C or D
87
        changes.
88
 
89
 
90
   BUGS
91
 
92
        When delivering an interrupt, this code assumes that there is only
93
        one processor (number 0).
94
 
95
   */
96
 
97
enum
98
{
99
  OPTION_OSC_SET = OPTION_START,
100
  OPTION_OSC_CLEAR,
101
  OPTION_OSC_INFO
102
};
103
 
104
static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
105
 
106
static const OPTION m68hc11_options[] =
107
{
108
  { {"osc-set", required_argument, NULL, OPTION_OSC_SET },
109
      '\0', "BIT,FREQ", "Set the oscillator on input port BIT",
110
      m68hc11_option_handler },
111
  { {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR },
112
      '\0', "BIT", "Clear oscillator on input port BIT",
113
      m68hc11_option_handler },
114
  { {"osc-info", no_argument, NULL, OPTION_OSC_INFO },
115
      '\0', NULL, "Print information about current input oscillators",
116
      m68hc11_option_handler },
117
 
118
  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
119
};
120
 
121
struct input_osc
122
{
123
  signed64         on_time;
124
  signed64         off_time;
125
  signed64         repeat;
126
  struct hw_event *event;
127
  const char      *name;
128
  uint8            mask;
129
  uint8            value;
130
  uint16           addr;
131
};
132
 
133
#define NR_PORT_A_OSC (4)
134
#define NR_PORT_B_OSC (0)
135
#define NR_PORT_C_OSC (8)
136
#define NR_PORT_D_OSC (6)
137
#define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC)
138
struct m68hc11cpu {
139
  /* Pending interrupts for delivery by event handler.  */
140
  int              pending_reset;
141
  int              pending_nmi;
142
  int              pending_level;
143
  struct hw_event  *event;
144
  unsigned_word    attach_address;
145
  int              attach_size;
146
  int              attach_space;
147
  int              last_oscillator;
148
  struct input_osc oscillators[NR_OSC];
149
};
150
 
151
 
152
 
153
/* input port ID's */
154
 
155
enum {
156
  RESET_PORT,
157
  NMI_PORT,
158
  IRQ_PORT,
159
  CPU_RESET_PORT,
160
  SET_PORT_A,
161
  SET_PORT_C,
162
  SET_PORT_D,
163
  CPU_WRITE_PORT,
164
  PORT_A,
165
  PORT_B,
166
  PORT_C,
167
  PORT_D,
168
  CAPTURE
169
};
170
 
171
 
172
static const struct hw_port_descriptor m68hc11cpu_ports[] = {
173
 
174
  /* Interrupt inputs.  */
175
  { "reset",     RESET_PORT,     0, input_port, },
176
  { "nmi",       NMI_PORT,       0, input_port, },
177
  { "irq",       IRQ_PORT,       0, input_port, },
178
 
179
  { "set-port-a", SET_PORT_A,    0, input_port, },
180
  { "set-port-c", SET_PORT_C,    0, input_port, },
181
  { "set-port-d", SET_PORT_D,    0, input_port, },
182
 
183
  { "cpu-write-port", CPU_WRITE_PORT,    0, input_port, },
184
 
185
  /* Events generated for connection to other devices.  */
186
  { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
187
 
188
  /* Events generated when the corresponding port is
189
     changed by the program.  */
190
  { "port-a",    PORT_A,         0, output_port, },
191
  { "port-b",    PORT_B,         0, output_port, },
192
  { "port-c",    PORT_C,         0, output_port, },
193
  { "port-d",    PORT_D,         0, output_port, },
194
 
195
  { "capture",   CAPTURE,        0, output_port, },
196
 
197
  { NULL, },
198
};
199
 
200
static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
201
static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
202
static hw_ioctl_method m68hc11_ioctl;
203
 
204
/* Finish off the partially created hw device.  Attach our local
205
   callbacks.  Wire up our port names etc.  */
206
 
207
static hw_port_event_method m68hc11cpu_port_event;
208
 
209
static void make_oscillator (struct m68hc11cpu *controller,
210
                             const char *id, uint16 addr, uint8 mask);
211
static struct input_osc *find_oscillator (struct m68hc11cpu *controller,
212
                                          const char *id);
213
static void reset_oscillators (struct hw *me);
214
 
215
static void
216
dv_m6811_attach_address_callback (struct hw *me,
217
                                  int level,
218
                                  int space,
219
                                  address_word addr,
220
                                  address_word nr_bytes,
221
                                  struct hw *client)
222
{
223
  HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
224
             level, space, (unsigned long) addr, (unsigned long) nr_bytes,
225
             hw_path (client)));
226
 
227
  if (space != io_map)
228
    {
229
      sim_core_attach (hw_system (me),
230
                       NULL, /*cpu*/
231
                       level,
232
                       access_read_write_exec,
233
                       space, addr,
234
                       nr_bytes,
235
                       0, /* modulo */
236
                       client,
237
                       NULL);
238
    }
239
  else
240
    {
241
      /*printf("Attach from sub device: %d\n", (long) addr);*/
242
      sim_core_attach (hw_system (me),
243
                       NULL, /*cpu*/
244
                       level,
245
                       access_io,
246
                       space, addr,
247
                       nr_bytes,
248
                       0, /* modulo */
249
                       client,
250
                       NULL);
251
    }
252
}
253
 
254
static void
255
dv_m6811_detach_address_callback (struct hw *me,
256
                                  int level,
257
                                  int space,
258
                                  address_word addr,
259
                                  address_word nr_bytes,
260
                                  struct hw *client)
261
{
262
  sim_core_detach (hw_system (me), NULL, /*cpu*/
263
                   level, space, addr);
264
}
265
 
266
static void
267
m68hc11_delete (struct hw* me)
268
{
269
  struct m68hc11cpu *controller;
270
 
271
  controller = hw_data (me);
272
 
273
  reset_oscillators (me);
274
  hw_detach_address (me, M6811_IO_LEVEL,
275
                     controller->attach_space,
276
                     controller->attach_address,
277
                     controller->attach_size, me);
278
}
279
 
280
 
281
static void
282
attach_m68hc11_regs (struct hw *me,
283
                     struct m68hc11cpu *controller)
284
{
285
  SIM_DESC sd;
286
  sim_cpu *cpu;
287
  reg_property_spec reg;
288
  const char *cpu_mode;
289
 
290
  if (hw_find_property (me, "reg") == NULL)
291
    hw_abort (me, "Missing \"reg\" property");
292
 
293
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
294
    hw_abort (me, "\"reg\" property must contain one addr/size entry");
295
 
296
  hw_unit_address_to_attach_address (hw_parent (me),
297
                                     &reg.address,
298
                                     &controller->attach_space,
299
                                     &controller->attach_address,
300
                                     me);
301
  hw_unit_size_to_attach_size (hw_parent (me),
302
                               &reg.size,
303
                               &controller->attach_size, me);
304
 
305
  hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
306
                     controller->attach_space,
307
                     controller->attach_address,
308
                     controller->attach_size,
309
                     me);
310
  set_hw_delete (me, m68hc11_delete);
311
 
312
  /* Get cpu frequency.  */
313
  sd = hw_system (me);
314
  cpu = STATE_CPU (sd, 0);
315
  if (hw_find_property (me, "clock") != NULL)
316
    {
317
      cpu->cpu_frequency = hw_find_integer_property (me, "clock");
318
    }
319
  else
320
    {
321
      cpu->cpu_frequency = 8*1000*1000;
322
    }
323
 
324
  if (hw_find_property (me, "use_bank") != NULL)
325
    hw_attach_address (hw_parent (me), 0,
326
                       exec_map,
327
                       cpu->bank_start,
328
                       cpu->bank_end - cpu->bank_start,
329
                       me);
330
 
331
  cpu_mode = "expanded";
332
  if (hw_find_property (me, "mode") != NULL)
333
    cpu_mode = hw_find_string_property (me, "mode");
334
 
335
  if (strcmp (cpu_mode, "test") == 0)
336
    cpu->cpu_mode = M6811_MDA | M6811_SMOD;
337
  else if (strcmp (cpu_mode, "bootstrap") == 0)
338
    cpu->cpu_mode = M6811_SMOD;
339
  else if (strcmp (cpu_mode, "single") == 0)
340
    cpu->cpu_mode = 0;
341
  else
342
    cpu->cpu_mode = M6811_MDA;
343
 
344
  controller->last_oscillator = 0;
345
 
346
  /* Create oscillators for input port A.  */
347
  make_oscillator (controller, "A7", M6811_PORTA, 0x80);
348
  make_oscillator (controller, "A2", M6811_PORTA, 0x04);
349
  make_oscillator (controller, "A1", M6811_PORTA, 0x02);
350
  make_oscillator (controller, "A0", M6811_PORTA, 0x01);
351
 
352
  /* port B is output only.  */
353
 
354
  /* Create oscillators for input port C.  */
355
  make_oscillator (controller, "C0", M6811_PORTC, 0x01);
356
  make_oscillator (controller, "C1", M6811_PORTC, 0x02);
357
  make_oscillator (controller, "C2", M6811_PORTC, 0x04);
358
  make_oscillator (controller, "C3", M6811_PORTC, 0x08);
359
  make_oscillator (controller, "C4", M6811_PORTC, 0x10);
360
  make_oscillator (controller, "C5", M6811_PORTC, 0x20);
361
  make_oscillator (controller, "C6", M6811_PORTC, 0x40);
362
  make_oscillator (controller, "C7", M6811_PORTC, 0x80);
363
 
364
  /* Create oscillators for input port D.  */
365
  make_oscillator (controller, "D0", M6811_PORTD, 0x01);
366
  make_oscillator (controller, "D1", M6811_PORTD, 0x02);
367
  make_oscillator (controller, "D2", M6811_PORTD, 0x04);
368
  make_oscillator (controller, "D3", M6811_PORTD, 0x08);
369
  make_oscillator (controller, "D4", M6811_PORTD, 0x10);
370
  make_oscillator (controller, "D5", M6811_PORTD, 0x20);
371
 
372
  /* Add oscillator commands.  */
373
  sim_add_option_table (sd, 0, m68hc11_options);
374
}
375
 
376
static void
377
m68hc11cpu_finish (struct hw *me)
378
{
379
  struct m68hc11cpu *controller;
380
 
381
  controller = HW_ZALLOC (me, struct m68hc11cpu);
382
  set_hw_data (me, controller);
383
  set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
384
  set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
385
  set_hw_ports (me, m68hc11cpu_ports);
386
  set_hw_port_event (me, m68hc11cpu_port_event);
387
  set_hw_attach_address (me, dv_m6811_attach_address_callback);
388
  set_hw_detach_address (me, dv_m6811_detach_address_callback);
389
#ifdef set_hw_ioctl
390
  set_hw_ioctl (me, m68hc11_ioctl);
391
#else
392
  me->to_ioctl = m68hc11_ioctl;
393
#endif
394
 
395
  /* Initialize the pending interrupt flags.  */
396
  controller->pending_level = 0;
397
  controller->pending_reset = 0;
398
  controller->pending_nmi = 0;
399
  controller->event = NULL;
400
 
401
  attach_m68hc11_regs (me, controller);
402
}
403
 
404
/* An event arrives on an interrupt port.  */
405
 
406
static void
407
deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
408
{
409
}
410
 
411
static void
412
make_oscillator (struct m68hc11cpu *controller, const char *name,
413
                 uint16 addr, uint8 mask)
414
{
415
  struct input_osc *osc;
416
 
417
  if (controller->last_oscillator >= NR_OSC)
418
    hw_abort (0, "Too many oscillators");
419
 
420
  osc = &controller->oscillators[controller->last_oscillator];
421
  osc->name = name;
422
  osc->addr = addr;
423
  osc->mask = mask;
424
  controller->last_oscillator++;
425
}
426
 
427
/* Find the oscillator given the input port name.  */
428
static struct input_osc *
429
find_oscillator (struct m68hc11cpu *controller, const char *name)
430
{
431
  int i;
432
 
433
  for (i = 0; i < controller->last_oscillator; i++)
434
    if (strcasecmp (controller->oscillators[i].name, name) == 0)
435
      return &controller->oscillators[i];
436
 
437
  return 0;
438
}
439
 
440
static void
441
oscillator_handler (struct hw *me, void *data)
442
{
443
  struct input_osc *osc = (struct input_osc*) data;
444
  SIM_DESC sd;
445
  sim_cpu *cpu;
446
  signed64 dt;
447
  uint8 val;
448
 
449
  sd = hw_system (me);
450
  cpu = STATE_CPU (sd, 0);
451
 
452
  /* Change the input bit.  */
453
  osc->value ^= osc->mask;
454
  val = cpu->ios[osc->addr] & ~osc->mask;
455
  val |= osc->value;
456
  m68hc11cpu_set_port (me, cpu, osc->addr, val);
457
 
458
  /* Setup event to toggle the bit.  */
459
  if (osc->value)
460
    dt = osc->on_time;
461
  else
462
    dt = osc->off_time;
463
 
464
  if (dt && --osc->repeat >= 0)
465
    {
466
      sim_events *events = STATE_EVENTS (sd);
467
 
468
      dt += events->nr_ticks_to_process;
469
      osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
470
    }
471
  else
472
    osc->event = 0;
473
}
474
 
475
static void
476
reset_oscillators (struct hw *me)
477
{
478
  struct m68hc11cpu *controller = hw_data (me);
479
  int i;
480
 
481
  for (i = 0; i < controller->last_oscillator; i++)
482
    {
483
      if (controller->oscillators[i].event)
484
        {
485
          hw_event_queue_deschedule (me, controller->oscillators[i].event);
486
          controller->oscillators[i].event = 0;
487
        }
488
    }
489
}
490
 
491
static void
492
m68hc11cpu_port_event (struct hw *me,
493
                       int my_port,
494
                       struct hw *source,
495
                       int source_port,
496
                       int level)
497
{
498
  struct m68hc11cpu *controller = hw_data (me);
499
  SIM_DESC sd;
500
  sim_cpu* cpu;
501
 
502
  sd  = hw_system (me);
503
  cpu = STATE_CPU (sd, 0);
504
  switch (my_port)
505
    {
506
    case RESET_PORT:
507
      HW_TRACE ((me, "port-in reset"));
508
 
509
      /* The reset is made in 3 steps:
510
         - First, cleanup the current sim_cpu struct.
511
         - Reset the devices.
512
         - Restart the cpu for the reset (get the CPU mode from the
513
           CONFIG register that gets initialized by EEPROM device).  */
514
      cpu_reset (cpu);
515
      reset_oscillators (me);
516
      hw_port_event (me, CPU_RESET_PORT, 1);
517
      cpu_restart (cpu);
518
      break;
519
 
520
    case NMI_PORT:
521
      controller->pending_nmi = 1;
522
      HW_TRACE ((me, "port-in nmi"));
523
      break;
524
 
525
    case IRQ_PORT:
526
      /* level == 0 means that the interrupt was cleared.  */
527
      if(level == 0)
528
        controller->pending_level = -1; /* signal end of interrupt */
529
      else
530
        controller->pending_level = level;
531
      HW_TRACE ((me, "port-in level=%d", level));
532
      break;
533
 
534
    case SET_PORT_A:
535
      m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
536
      break;
537
 
538
    case SET_PORT_C:
539
      m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
540
      break;
541
 
542
    case SET_PORT_D:
543
      m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
544
      break;
545
 
546
    case CPU_WRITE_PORT:
547
      break;
548
 
549
    default:
550
      hw_abort (me, "bad switch");
551
      break;
552
    }
553
 
554
  /* Schedule an event to be delivered immediately after current
555
     instruction.  */
556
  if(controller->event != NULL)
557
    hw_event_queue_deschedule(me, controller->event);
558
  controller->event =
559
    hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
560
}
561
 
562
 
563
io_reg_desc config_desc[] = {
564
  { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
565
  { M6811_NOCOP, "NOCOP ", "COP System Disable" },
566
  { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
567
  { M6811_EEON,  "EEON  ", "Enable On-chip EEprom" },
568
  { 0,  0, 0 }
569
};
570
 
571
io_reg_desc hprio_desc[] = {
572
  { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
573
  { M6811_SMOD,  "SMOD  ", "Special Mode" },
574
  { M6811_MDA,   "MDA   ", "Mode Select A" },
575
  { M6811_IRV,   "IRV   ", "Internal Read Visibility" },
576
  { 0,  0, 0 }
577
};
578
 
579
io_reg_desc option_desc[] = {
580
  { M6811_ADPU,  "ADPU  ", "A/D Powerup" },
581
  { M6811_CSEL,  "CSEL  ", "A/D/EE Charge pump clock source select" },
582
  { M6811_IRQE,  "IRQE  ", "IRQ Edge/Level sensitive" },
583
  { M6811_DLY,   "DLY   ", "Stop exit turn on delay" },
584
  { M6811_CME,   "CME   ", "Clock Monitor Enable" },
585
  { M6811_CR1,   "CR1   ", "COP timer rate select (CR1)" },
586
  { M6811_CR0,   "CR0   ", "COP timer rate select (CR0)" },
587
  { 0,  0, 0 }
588
};
589
 
590
static void
591
m68hc11_info (struct hw *me)
592
{
593
  SIM_DESC sd;
594
  uint16 base = 0;
595
  sim_cpu *cpu;
596
  struct m68hc11sio *controller;
597
  uint8 val;
598
 
599
  sd = hw_system (me);
600
  cpu = STATE_CPU (sd, 0);
601
  controller = hw_data (me);
602
 
603
  base = cpu_get_io_base (cpu);
604
  sim_io_printf (sd, "M68HC11:\n");
605
 
606
  val = cpu->ios[M6811_HPRIO];
607
  print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
608
  switch (cpu->cpu_mode)
609
    {
610
    case M6811_MDA | M6811_SMOD:
611
      sim_io_printf (sd, "[test]\n");
612
      break;
613
    case M6811_SMOD:
614
      sim_io_printf (sd, "[bootstrap]\n");
615
      break;
616
    case M6811_MDA:
617
      sim_io_printf (sd, "[extended]\n");
618
      break;
619
    default:
620
      sim_io_printf (sd, "[single]\n");
621
      break;
622
    }
623
 
624
  val = cpu->ios[M6811_CONFIG];
625
  print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
626
  sim_io_printf (sd, "\n");
627
 
628
  val = cpu->ios[M6811_OPTION];
629
  print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
630
  sim_io_printf (sd, "\n");
631
 
632
  val = cpu->ios[M6811_INIT];
633
  print_io_byte (sd, "INIT  ", 0, val, base + M6811_INIT);
634
  sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
635
                 (((uint16) (val & 0xF0)) << 8),
636
                 (((uint16) (val & 0x0F)) << 12));
637
 
638
 
639
  cpu_info (sd, cpu);
640
  interrupts_info (sd, &cpu->cpu_interrupts);
641
}
642
 
643
static int
644
m68hc11_ioctl (struct hw *me,
645
               hw_ioctl_request request,
646
               va_list ap)
647
{
648
  m68hc11_info (me);
649
  return 0;
650
}
651
 
652
/* Setup an oscillator on an input port.
653
 
654
   TON represents the time in seconds that the input port should be set to 1.
655
   TOFF is the time in seconds for the input port to be set to 0.
656
 
657
   The oscillator frequency is therefore 1 / (ton + toff).
658
 
659
   REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
660
   stops.  */
661
int
662
m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
663
                           double ton, double toff, signed64 repeat)
664
{
665
  sim_cpu *cpu;
666
  struct input_osc *osc;
667
  double f;
668
 
669
  cpu = STATE_CPU (sd, 0);
670
 
671
  /* Find oscillator that corresponds to the input port.  */
672
  osc = find_oscillator (hw_data (cpu->hw_cpu), port);
673
  if (osc == 0)
674
    return -1;
675
 
676
  /* Compute the ON time in cpu cycles.  */
677
  f = (double) (cpu->cpu_frequency) * ton;
678
  osc->on_time = (signed64) (f / 4.0);
679
  if (osc->on_time < 1)
680
    osc->on_time = 1;
681
 
682
  /* Compute the OFF time in cpu cycles.  */
683
  f = (double) (cpu->cpu_frequency) * toff;
684
  osc->off_time = (signed64) (f / 4.0);
685
  if (osc->off_time < 1)
686
    osc->off_time = 1;
687
 
688
  osc->repeat = repeat;
689
  if (osc->event)
690
    hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
691
 
692
  osc->event = hw_event_queue_schedule (cpu->hw_cpu,
693
                                        osc->value ? osc->on_time
694
                                        : osc->off_time,
695
                                        oscillator_handler, osc);
696
  return 0;
697
}
698
 
699
/* Clear the oscillator.  */
700
int
701
m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
702
{
703
  sim_cpu *cpu;
704
  struct input_osc *osc;
705
 
706
  cpu = STATE_CPU (sd, 0);
707
  osc = find_oscillator (hw_data (cpu->hw_cpu), port);
708
  if (osc == 0)
709
    return -1;
710
 
711
  if (osc->event)
712
    hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
713
  osc->event = 0;
714
  osc->repeat = 0;
715
  return 0;
716
}
717
 
718
static int
719
get_frequency (const char *s, double *f)
720
{
721
  char *p;
722
 
723
  *f = strtod (s, &p);
724
  if (s == p)
725
    return -1;
726
 
727
  if (*p)
728
    {
729
      if (strcasecmp (p, "khz") == 0)
730
        *f = *f * 1000.0;
731
      else if (strcasecmp (p, "mhz") == 0)
732
        *f = *f  * 1000000.0;
733
      else if (strcasecmp (p, "hz") != 0)
734
        return -1;
735
    }
736
  return 0;
737
}
738
 
739
static SIM_RC
740
m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
741
                        int opt, char *arg, int is_command)
742
{
743
  struct m68hc11cpu *controller;
744
  double f;
745
  char *p;
746
  int i;
747
  int title_printed = 0;
748
 
749
  if (cpu == 0)
750
    cpu = STATE_CPU (sd, 0);
751
 
752
  controller = hw_data (cpu->hw_cpu);
753
  switch (opt)
754
    {
755
    case OPTION_OSC_SET:
756
      p = strchr (arg, ',');
757
      if (p)
758
        *p++ = 0;
759
 
760
      if (p == 0)
761
        sim_io_eprintf (sd, "No frequency specified\n");
762
      else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
763
        sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
764
      else if (m68hc11cpu_set_oscillator (sd, arg,
765
                                          1.0 / (f * 2.0),
766
                                          1.0 / (f * 2.0), LONG_MAX))
767
        sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
768
      break;
769
 
770
    case OPTION_OSC_CLEAR:
771
      if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
772
        sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
773
      break;
774
 
775
    case OPTION_OSC_INFO:
776
      for (i = 0; i < controller->last_oscillator; i++)
777
        {
778
          signed64 t;
779
          struct input_osc *osc;
780
 
781
          osc = &controller->oscillators[i];
782
          if (osc->event)
783
            {
784
              double f;
785
              int cur_value;
786
              int next_value;
787
              char freq[32];
788
 
789
              if (title_printed == 0)
790
                {
791
                  title_printed = 1;
792
                  sim_io_printf (sd, " PORT  Frequency   Current"
793
                                 "    Next    Transition time\n");
794
                }
795
 
796
              f = (double) (osc->on_time + osc->off_time);
797
              f = (double) (cpu->cpu_frequency / 4) / f;
798
              t = hw_event_remain_time (cpu->hw_cpu, osc->event);
799
 
800
              if (f > 10000.0)
801
                sprintf (freq, "%6.2f", f / 1000.0);
802
              else
803
                sprintf (freq, "%6.2f", f);
804
              cur_value = osc->value ? 1 : 0;
805
              next_value = osc->value ? 0 : 1;
806
              if (f > 10000.0)
807
                sim_io_printf (sd, " %4.4s  %8.8s khz"
808
                               "      %d       %d    %35.35s\n",
809
                               osc->name, freq,
810
                               cur_value, next_value,
811
                               cycle_to_string (cpu, t,
812
                                                PRINT_TIME | PRINT_CYCLE));
813
              else
814
                sim_io_printf (sd, " %4.4s  %8.8s hz "
815
                               "      %d       %d    %35.35s\n",
816
                               osc->name, freq,
817
                               cur_value, next_value,
818
                               cycle_to_string (cpu, t,
819
                                                PRINT_TIME | PRINT_CYCLE));
820
            }
821
        }
822
      break;
823
    }
824
 
825
  return SIM_RC_OK;
826
}
827
 
828
/* generic read/write */
829
 
830
static unsigned
831
m68hc11cpu_io_read_buffer (struct hw *me,
832
                           void *dest,
833
                           int space,
834
                           unsigned_word base,
835
                           unsigned nr_bytes)
836
{
837
  SIM_DESC sd;
838
  struct m68hc11cpu *controller = hw_data (me);
839
  sim_cpu *cpu;
840
  unsigned byte = 0;
841
  int result;
842
 
843
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
844
 
845
  sd  = hw_system (me);
846
  cpu = STATE_CPU (sd, 0);
847
 
848
  if (base >= cpu->bank_start && base < cpu->bank_end)
849
    {
850
      address_word virt_addr = phys_to_virt (cpu, base);
851
      if (virt_addr != base)
852
        return sim_core_read_buffer (sd, cpu, space, dest,
853
                                     virt_addr, nr_bytes);
854
    }
855
 
856
  /* Handle reads for the sub-devices.  */
857
  base -= controller->attach_address;
858
  result = sim_core_read_buffer (sd, cpu,
859
                                 io_map, dest, base, nr_bytes);
860
  if (result > 0)
861
    return result;
862
 
863
  while (nr_bytes)
864
    {
865
      if (base >= controller->attach_size)
866
        break;
867
 
868
      memcpy (dest, &cpu->ios[base], 1);
869
      dest = (char*) dest + 1;
870
      base++;
871
      byte++;
872
      nr_bytes--;
873
    }
874
  return byte;
875
}
876
 
877
void
878
m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
879
                     unsigned addr, uint8 val)
880
{
881
  uint8 mask;
882
  uint8 delta;
883
  int check_interrupts = 0;
884
  int i;
885
 
886
  switch (addr)
887
    {
888
    case M6811_PORTA:
889
      if (cpu->ios[M6811_PACTL] & M6811_DDRA7)
890
        mask = 3;
891
      else
892
        mask = 0x83;
893
 
894
      val = val & mask;
895
      val |= cpu->ios[M6811_PORTA] & ~mask;
896
      delta = val ^ cpu->ios[M6811_PORTA];
897
      cpu->ios[M6811_PORTA] = val;
898
      if (delta & 0x80)
899
        {
900
          /* Pulse accumulator is enabled.  */
901
          if ((cpu->ios[M6811_PACTL] & M6811_PAEN)
902
              && !(cpu->ios[M6811_PACTL] & M6811_PAMOD))
903
            {
904
              int inc;
905
 
906
              /* Increment event counter according to rising/falling edge.  */
907
              if (cpu->ios[M6811_PACTL] & M6811_PEDGE)
908
                inc = (val & 0x80) ? 1 : 0;
909
              else
910
                inc = (val & 0x80) ? 0 : 1;
911
 
912
              cpu->ios[M6811_PACNT] += inc;
913
 
914
              /* Event counter overflowed.  */
915
              if (inc && cpu->ios[M6811_PACNT] == 0)
916
                {
917
                  cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
918
                  check_interrupts = 1;
919
                }
920
            }
921
        }
922
 
923
      /* Scan IC3, IC2 and IC1.  Bit number is 3 - i.  */
924
      for (i = 0; i < 3; i++)
925
        {
926
          uint8 mask = (1 << i);
927
 
928
          if (delta & mask)
929
            {
930
              uint8 edge;
931
              int captured;
932
 
933
              edge = cpu->ios[M6811_TCTL2];
934
              edge = (edge >> (2 * i)) & 0x3;
935
              switch (edge)
936
                {
937
                case 0:
938
                  captured = 0;
939
                  break;
940
                case 1:
941
                  captured = (val & mask) != 0;
942
                  break;
943
                case 2:
944
                  captured = (val & mask) == 0;
945
                  break;
946
                default:
947
                  captured = 1;
948
                  break;
949
                }
950
              if (captured)
951
                {
952
                  cpu->ios[M6811_TFLG1] |= (1 << i);
953
                  hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
954
                  check_interrupts = 1;
955
                }
956
            }
957
        }
958
      break;
959
 
960
    case M6811_PORTC:
961
      mask = cpu->ios[M6811_DDRC];
962
      val = val & mask;
963
      val |= cpu->ios[M6811_PORTC] & ~mask;
964
      cpu->ios[M6811_PORTC] = val;
965
      break;
966
 
967
    case M6811_PORTD:
968
      mask = cpu->ios[M6811_DDRD];
969
      val = val & mask;
970
      val |= cpu->ios[M6811_PORTD] & ~mask;
971
      cpu->ios[M6811_PORTD] = val;
972
      break;
973
 
974
    default:
975
      break;
976
    }
977
 
978
  if (check_interrupts)
979
    interrupts_update_pending (&cpu->cpu_interrupts);
980
}
981
 
982
static void
983
m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
984
                     unsigned_word addr, uint8 val)
985
{
986
  switch (addr)
987
    {
988
    case M6811_PORTA:
989
      hw_port_event (me, PORT_A, val);
990
      break;
991
 
992
    case M6811_PIOC:
993
      break;
994
 
995
    case M6811_PORTC:
996
      hw_port_event (me, PORT_C, val);
997
      break;
998
 
999
    case M6811_PORTB:
1000
      hw_port_event (me, PORT_B, val);
1001
      break;
1002
 
1003
    case M6811_PORTCL:
1004
      break;
1005
 
1006
    case M6811_DDRC:
1007
      break;
1008
 
1009
    case M6811_PORTD:
1010
      hw_port_event (me, PORT_D, val);
1011
      break;
1012
 
1013
    case M6811_DDRD:
1014
      break;
1015
 
1016
    case M6811_TMSK2:
1017
 
1018
      break;
1019
 
1020
      /* Change the RAM and I/O mapping.  */
1021
    case M6811_INIT:
1022
      {
1023
        uint8 old_bank = cpu->ios[M6811_INIT];
1024
 
1025
        cpu->ios[M6811_INIT] = val;
1026
 
1027
        /* Update IO mapping.  Detach from the old address
1028
           and attach to the new one.  */
1029
        if ((old_bank & 0x0F) != (val & 0x0F))
1030
          {
1031
            struct m68hc11cpu *controller = hw_data (me);
1032
 
1033
            hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
1034
                               controller->attach_space,
1035
                               controller->attach_address,
1036
                               controller->attach_size,
1037
                               me);
1038
            controller->attach_address = (val & 0x0F0) << 12;
1039
            hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
1040
                               controller->attach_space,
1041
                               controller->attach_address,
1042
                               controller->attach_size,
1043
                               me);
1044
          }
1045
        if ((old_bank & 0xF0) != (val & 0xF0))
1046
          {
1047
            ;
1048
          }
1049
        return;
1050
      }
1051
 
1052
    /* Writing the config is similar to programing the eeprom.
1053
       The config register value is the last byte of the EEPROM.
1054
       This last byte is not mapped in memory (that's why we have
1055
       to add '1' to 'end_addr').  */
1056
    case M6811_CONFIG:
1057
      {
1058
        return;
1059
      }
1060
 
1061
 
1062
      /* COP reset.  */
1063
    case M6811_COPRST:
1064
      if (val == 0xAA && cpu->ios[addr] == 0x55)
1065
        {
1066
          val = 0;
1067
          /* COP reset here.  */
1068
        }
1069
      break;
1070
 
1071
    default:
1072
      break;
1073
 
1074
    }
1075
  cpu->ios[addr] = val;
1076
}
1077
 
1078
static unsigned
1079
m68hc11cpu_io_write_buffer (struct hw *me,
1080
                            const void *source,
1081
                            int space,
1082
                            unsigned_word base,
1083
                            unsigned nr_bytes)
1084
{
1085
  SIM_DESC sd;
1086
  struct m68hc11cpu *controller = hw_data (me);
1087
  unsigned byte;
1088
  sim_cpu *cpu;
1089
  int result;
1090
 
1091
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
1092
 
1093
  sd = hw_system (me);
1094
  cpu = STATE_CPU (sd, 0);
1095
 
1096
  if (base >= cpu->bank_start && base < cpu->bank_end)
1097
    {
1098
      address_word virt_addr = phys_to_virt (cpu, base);
1099
      if (virt_addr != base)
1100
        return sim_core_write_buffer (sd, cpu, space, source,
1101
                                      virt_addr, nr_bytes);
1102
    }
1103
  base -= controller->attach_address;
1104
  result = sim_core_write_buffer (sd, cpu,
1105
                                  io_map, source, base, nr_bytes);
1106
  if (result > 0)
1107
    return result;
1108
 
1109
  byte = 0;
1110
  while (nr_bytes)
1111
    {
1112
      uint8 val;
1113
      if (base >= controller->attach_size)
1114
        break;
1115
 
1116
      val = *((uint8*) source);
1117
      m68hc11cpu_io_write (me, cpu, base, val);
1118
      source = (char*) source + 1;
1119
      base++;
1120
      byte++;
1121
      nr_bytes--;
1122
    }
1123
  return byte;
1124
}
1125
 
1126
const struct hw_descriptor dv_m68hc11_descriptor[] = {
1127
  { "m68hc11", m68hc11cpu_finish },
1128
  { "m68hc12", m68hc11cpu_finish },
1129
  { NULL },
1130
};
1131
 

powered by: WebSVN 2.1.0

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