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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [m68hc11/] [dv-m68hc11eepr.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/*  dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM.
2
    Copyright (C) 1999, 2000, 2001, 2002, 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 "hw-main.h"
25
#include "sim-assert.h"
26
#include "sim-events.h"
27
 
28
#include <unistd.h>
29
#include <fcntl.h>
30
#include <errno.h>
31
 
32
 
33
 
34
/* DEVICE
35
 
36
        m68hc11eepr - m68hc11 EEPROM
37
 
38
 
39
   DESCRIPTION
40
 
41
        Implements the 68HC11 eeprom device described in the m68hc11
42
        user guide (Chapter 4 in the pink book).
43
 
44
 
45
   PROPERTIES
46
 
47
   reg <base> <length>
48
 
49
        Base of eeprom and its length.
50
 
51
   file <path>
52
 
53
        Path of the EEPROM file.  The default is 'm6811.eeprom'.
54
 
55
 
56
   PORTS
57
 
58
        None
59
 
60
   */
61
 
62
 
63
 
64
/* static functions */
65
 
66
 
67
/* port ID's */
68
 
69
enum
70
{
71
  RESET_PORT
72
};
73
 
74
 
75
static const struct hw_port_descriptor m68hc11eepr_ports[] =
76
{
77
  { "reset", RESET_PORT, 0, input_port, },
78
  { NULL, },
79
};
80
 
81
 
82
 
83
/* The timer/counter register internal state.  Note that we store
84
   state using the control register images, in host endian order.  */
85
 
86
struct m68hc11eepr
87
{
88
  address_word  base_address; /* control register base */
89
  int           attach_space;
90
  unsigned      size;
91
  int           mapped;
92
 
93
  /* Current state of the eeprom programing:
94
     - eeprom_wmode indicates whether the EEPROM address and byte have
95
       been latched.
96
     - eeprom_waddr indicates the EEPROM address that was latched
97
       and eeprom_wbyte is the byte that was latched.
98
     - eeprom_wcycle indicates the CPU absolute cycle type when
99
       the high voltage was applied (successfully) on the EEPROM.
100
 
101
     These data members are setup only when we detect good EEPROM programing
102
     conditions (see Motorola EEPROM Programming and PPROG register usage).
103
     When the high voltage is switched off, we look at the CPU absolute
104
     cycle time to see if the EEPROM command must succeeds or not.
105
     The EEPROM content is updated and saved only at that time.
106
     (EEPROM command is: byte zero bits program, byte erase, row erase
107
     and bulk erase).
108
 
109
     The CONFIG register is programmed in the same way.  It is physically
110
     located at the end of the EEPROM (eeprom size + 1).  It is not mapped
111
     in memory but it's saved in the EEPROM file.  */
112
  unsigned long         eeprom_wcycle;
113
  uint16                eeprom_waddr;
114
  uint8                 eeprom_wbyte;
115
  uint8                 eeprom_wmode;
116
 
117
  uint8*                eeprom;
118
 
119
  /* Minimum time in CPU cycles for programming the EEPROM.  */
120
  unsigned long         eeprom_min_cycles;
121
 
122
  const char*           file_name;
123
};
124
 
125
 
126
 
127
/* Finish off the partially created hw device.  Attach our local
128
   callbacks.  Wire up our port names etc.  */
129
 
130
static hw_io_read_buffer_method m68hc11eepr_io_read_buffer;
131
static hw_io_write_buffer_method m68hc11eepr_io_write_buffer;
132
static hw_ioctl_method m68hc11eepr_ioctl;
133
 
134
/* Read or write the memory bank content from/to a file.
135
   Returns 0 if the operation succeeded and -1 if it failed.  */
136
static int
137
m6811eepr_memory_rw (struct m68hc11eepr *controller, int mode)
138
{
139
  const char *name = controller->file_name;
140
  int fd;
141
  size_t size;
142
 
143
  size = controller->size;
144
  fd = open (name, mode, 0644);
145
  if (fd < 0)
146
    {
147
      if (mode == O_RDONLY)
148
        {
149
          memset (controller->eeprom, 0xFF, size);
150
          /* Default value for CONFIG register (0xFF should be ok):
151
             controller->eeprom[size - 1] = M6811_NOSEC | M6811_NOCOP
152
                                            | M6811_ROMON | M6811_EEON;  */
153
          return 0;
154
        }
155
      return -1;
156
    }
157
 
158
  if (mode == O_RDONLY)
159
    {
160
      if (read (fd, controller->eeprom, size) != size)
161
        {
162
          close (fd);
163
          return -1;
164
        }
165
    }
166
  else
167
    {
168
      if (write (fd, controller->eeprom, size) != size)
169
        {
170
          close (fd);
171
          return -1;
172
        }
173
    }
174
  close (fd);
175
 
176
  return 0;
177
}
178
 
179
 
180
 
181
 
182
static void
183
attach_m68hc11eepr_regs (struct hw *me,
184
                         struct m68hc11eepr *controller)
185
{
186
  unsigned_word attach_address;
187
  int attach_space;
188
  unsigned attach_size;
189
  reg_property_spec reg;
190
 
191
  if (hw_find_property (me, "reg") == NULL)
192
    hw_abort (me, "Missing \"reg\" property");
193
 
194
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
195
    hw_abort (me, "\"reg\" property must contain one addr/size entry");
196
 
197
  hw_unit_address_to_attach_address (hw_parent (me),
198
                                     &reg.address,
199
                                     &attach_space,
200
                                     &attach_address,
201
                                     me);
202
  hw_unit_size_to_attach_size (hw_parent (me),
203
                               &reg.size,
204
                               &attach_size, me);
205
 
206
  /* Attach the two IO registers that control the EEPROM.
207
     The EEPROM is only attached at reset time because it may
208
     be enabled/disabled by the EEON bit in the CONFIG register.  */
209
  hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
210
                     io_map, M6811_PPROG, 1, me);
211
  hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
212
                     io_map, M6811_CONFIG, 1, me);
213
 
214
  if (hw_find_property (me, "file") == NULL)
215
    controller->file_name = "m6811.eeprom";
216
  else
217
    controller->file_name = hw_find_string_property (me, "file");
218
 
219
  controller->attach_space = attach_space;
220
  controller->base_address = attach_address;
221
  controller->eeprom = (char*) hw_malloc (me, attach_size + 1);
222
  controller->eeprom_min_cycles = 10000;
223
  controller->size = attach_size + 1;
224
  controller->mapped = 0;
225
 
226
  m6811eepr_memory_rw (controller, O_RDONLY);
227
}
228
 
229
 
230
/* An event arrives on an interrupt port.  */
231
 
232
static void
233
m68hc11eepr_port_event (struct hw *me,
234
                        int my_port,
235
                        struct hw *source,
236
                        int source_port,
237
                        int level)
238
{
239
  SIM_DESC sd;
240
  struct m68hc11eepr *controller;
241
  sim_cpu *cpu;
242
 
243
  controller = hw_data (me);
244
  sd         = hw_system (me);
245
  cpu        = STATE_CPU (sd, 0);
246
  switch (my_port)
247
    {
248
    case RESET_PORT:
249
      {
250
        HW_TRACE ((me, "EEPROM reset"));
251
 
252
        /* Re-read the EEPROM from the file.  This gives the chance
253
           to users to erase this file before doing a reset and have
254
           a fresh EEPROM taken into account.  */
255
        m6811eepr_memory_rw (controller, O_RDONLY);
256
 
257
        /* Reset the state of EEPROM programmer.  The CONFIG register
258
           is also initialized from the EEPROM/file content.  */
259
        cpu->ios[M6811_PPROG]    = 0;
260
        if (cpu->cpu_use_local_config)
261
          cpu->ios[M6811_CONFIG] = cpu->cpu_config;
262
        else
263
          cpu->ios[M6811_CONFIG]   = controller->eeprom[controller->size-1];
264
        controller->eeprom_wmode = 0;
265
        controller->eeprom_waddr = 0;
266
        controller->eeprom_wbyte = 0;
267
 
268
        /* Attach or detach to the bus depending on the EEPROM enable bit.
269
           The EEPROM CONFIG register is still enabled and can be programmed
270
           for a next configuration (taken into account only after a reset,
271
           see Motorola spec).  */
272
        if (!(cpu->ios[M6811_CONFIG] & M6811_EEON))
273
          {
274
            if (controller->mapped)
275
              hw_detach_address (hw_parent (me), M6811_EEPROM_LEVEL,
276
                                 controller->attach_space,
277
                                 controller->base_address,
278
                                 controller->size - 1,
279
                                 me);
280
            controller->mapped = 0;
281
          }
282
        else
283
          {
284
            if (!controller->mapped)
285
              hw_attach_address (hw_parent (me), M6811_EEPROM_LEVEL,
286
                                 controller->attach_space,
287
                                 controller->base_address,
288
                                 controller->size - 1,
289
                                 me);
290
            controller->mapped = 1;
291
          }
292
        break;
293
      }
294
 
295
    default:
296
      hw_abort (me, "Event on unknown port %d", my_port);
297
      break;
298
    }
299
}
300
 
301
 
302
static void
303
m68hc11eepr_finish (struct hw *me)
304
{
305
  struct m68hc11eepr *controller;
306
 
307
  controller = HW_ZALLOC (me, struct m68hc11eepr);
308
  set_hw_data (me, controller);
309
  set_hw_io_read_buffer (me, m68hc11eepr_io_read_buffer);
310
  set_hw_io_write_buffer (me, m68hc11eepr_io_write_buffer);
311
  set_hw_ports (me, m68hc11eepr_ports);
312
  set_hw_port_event (me, m68hc11eepr_port_event);
313
#ifdef set_hw_ioctl
314
  set_hw_ioctl (me, m68hc11eepr_ioctl);
315
#else
316
  me->to_ioctl = m68hc11eepr_ioctl;
317
#endif
318
 
319
  attach_m68hc11eepr_regs (me, controller);
320
}
321
 
322
 
323
 
324
static io_reg_desc pprog_desc[] = {
325
  { M6811_BYTE,  "BYTE  ", "Byte Program Mode" },
326
  { M6811_ROW,   "ROW   ", "Row Program Mode" },
327
  { M6811_ERASE, "ERASE ", "Erase Mode" },
328
  { M6811_EELAT, "EELAT ", "EEProm Latch Control" },
329
  { M6811_EEPGM, "EEPGM ", "EEProm Programming Voltable Enable" },
330
  { 0,  0, 0 }
331
};
332
extern io_reg_desc config_desc[];
333
 
334
 
335
/* Describe the state of the EEPROM device.  */
336
static void
337
m68hc11eepr_info (struct hw *me)
338
{
339
  SIM_DESC sd;
340
  uint16 base = 0;
341
  sim_cpu *cpu;
342
  struct m68hc11eepr *controller;
343
  uint8 val;
344
 
345
  sd         = hw_system (me);
346
  cpu        = STATE_CPU (sd, 0);
347
  controller = hw_data (me);
348
  base       = cpu_get_io_base (cpu);
349
 
350
  sim_io_printf (sd, "M68HC11 EEprom:\n");
351
 
352
  val = cpu->ios[M6811_PPROG];
353
  print_io_byte (sd, "PPROG  ", pprog_desc, val, base + M6811_PPROG);
354
  sim_io_printf (sd, "\n");
355
 
356
  val = cpu->ios[M6811_CONFIG];
357
  print_io_byte (sd, "CONFIG ", config_desc, val, base + M6811_CONFIG);
358
  sim_io_printf (sd, "\n");
359
 
360
  val = controller->eeprom[controller->size - 1];
361
  print_io_byte (sd, "(*NEXT*) ", config_desc, val, base + M6811_CONFIG);
362
  sim_io_printf (sd, "\n");
363
 
364
  /* Describe internal state of EEPROM.  */
365
  if (controller->eeprom_wmode)
366
    {
367
      if (controller->eeprom_waddr == controller->size - 1)
368
        sim_io_printf (sd, "  Programming CONFIG register ");
369
      else
370
        sim_io_printf (sd, "  Programming: 0x%04x ",
371
                       controller->eeprom_waddr + controller->base_address);
372
 
373
      sim_io_printf (sd, "with 0x%02x\n",
374
                     controller->eeprom_wbyte);
375
    }
376
 
377
  sim_io_printf (sd, "  EEProm file: %s\n",
378
                 controller->file_name);
379
}
380
 
381
static int
382
m68hc11eepr_ioctl (struct hw *me,
383
                   hw_ioctl_request request,
384
                   va_list ap)
385
{
386
  m68hc11eepr_info (me);
387
  return 0;
388
}
389
 
390
/* generic read/write */
391
 
392
static unsigned
393
m68hc11eepr_io_read_buffer (struct hw *me,
394
                            void *dest,
395
                            int space,
396
                            unsigned_word base,
397
                            unsigned nr_bytes)
398
{
399
  SIM_DESC sd;
400
  struct m68hc11eepr *controller;
401
  sim_cpu *cpu;
402
 
403
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
404
 
405
  sd         = hw_system (me);
406
  controller = hw_data (me);
407
  cpu        = STATE_CPU (sd, 0);
408
 
409
  if (space == io_map)
410
    {
411
      unsigned cnt = 0;
412
 
413
      while (nr_bytes != 0)
414
        {
415
          switch (base)
416
            {
417
            case M6811_PPROG:
418
            case M6811_CONFIG:
419
              *((uint8*) dest) = cpu->ios[base];
420
              break;
421
 
422
            default:
423
              hw_abort (me, "reading wrong register 0x%04x", base);
424
            }
425
          dest = (uint8*) (dest) + 1;
426
          base++;
427
          nr_bytes--;
428
          cnt++;
429
        }
430
      return cnt;
431
    }
432
 
433
  /* In theory, we can't read the EEPROM when it's being programmed.  */
434
  if ((cpu->ios[M6811_PPROG] & M6811_EELAT) != 0
435
      && cpu_is_running (cpu))
436
    {
437
      sim_memory_error (cpu, SIM_SIGBUS, base,
438
                        "EEprom not configured for reading");
439
    }
440
 
441
  base = base - controller->base_address;
442
  memcpy (dest, &controller->eeprom[base], nr_bytes);
443
  return nr_bytes;
444
}
445
 
446
 
447
static unsigned
448
m68hc11eepr_io_write_buffer (struct hw *me,
449
                             const void *source,
450
                             int space,
451
                             unsigned_word base,
452
                             unsigned nr_bytes)
453
{
454
  SIM_DESC sd;
455
  struct m68hc11eepr *controller;
456
  sim_cpu *cpu;
457
  uint8 val;
458
 
459
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
460
 
461
  sd         = hw_system (me);
462
  controller = hw_data (me);
463
  cpu        = STATE_CPU (sd, 0);
464
 
465
  /* Programming several bytes at a time is not possible.  */
466
  if (space != io_map && nr_bytes != 1)
467
    {
468
      sim_memory_error (cpu, SIM_SIGBUS, base,
469
                        "EEprom write error (only 1 byte can be programmed)");
470
      return 0;
471
    }
472
 
473
  if (nr_bytes != 1)
474
    hw_abort (me, "Cannot write more than 1 byte to EEPROM device at a time");
475
 
476
  val = *((const uint8*) source);
477
 
478
  /* Write to the EEPROM control register.  */
479
  if (space == io_map && base == M6811_PPROG)
480
    {
481
      uint8 wrong_bits;
482
      uint16 addr;
483
 
484
      addr = base + cpu_get_io_base (cpu);
485
 
486
      /* Setting EELAT and EEPGM at the same time is an error.
487
         Clearing them both is ok.  */
488
      wrong_bits = (cpu->ios[M6811_PPROG] ^ val) & val;
489
      wrong_bits &= (M6811_EELAT | M6811_EEPGM);
490
 
491
      if (wrong_bits == (M6811_EEPGM|M6811_EELAT))
492
        {
493
          sim_memory_error (cpu, SIM_SIGBUS, addr,
494
                            "Wrong eeprom programing value");
495
          return 0;
496
        }
497
 
498
      if ((val & M6811_EELAT) == 0)
499
        {
500
          val = 0;
501
        }
502
      if ((val & M6811_EEPGM) && !(cpu->ios[M6811_PPROG] & M6811_EELAT))
503
        {
504
          sim_memory_error (cpu, SIM_SIGBUS, addr,
505
                            "EEProm high voltage applied after EELAT");
506
        }
507
      if ((val & M6811_EEPGM) && controller->eeprom_wmode == 0)
508
        {
509
          sim_memory_error (cpu, SIM_SIGSEGV, addr,
510
                            "EEProm high voltage applied without address");
511
        }
512
      if (val & M6811_EEPGM)
513
        {
514
          controller->eeprom_wcycle = cpu_current_cycle (cpu);
515
        }
516
      else if (cpu->ios[M6811_PPROG] & M6811_PPROG)
517
        {
518
          int i;
519
          unsigned long t = cpu_current_cycle (cpu);
520
 
521
          t -= controller->eeprom_wcycle;
522
          if (t < controller->eeprom_min_cycles)
523
            {
524
              sim_memory_error (cpu, SIM_SIGILL, addr,
525
                                "EEprom programmed only for %lu cycles",
526
                                t);
527
            }
528
 
529
          /* Program the byte by clearing some bits.  */
530
          if (!(cpu->ios[M6811_PPROG] & M6811_ERASE))
531
            {
532
              controller->eeprom[controller->eeprom_waddr]
533
                &= controller->eeprom_wbyte;
534
            }
535
 
536
          /* Erase a byte, row or the complete eeprom.  Erased value is 0xFF.
537
             Ignore row or complete eeprom erase when we are programming the
538
             CONFIG register (last EEPROM byte).  */
539
          else if ((cpu->ios[M6811_PPROG] & M6811_BYTE)
540
                   || controller->eeprom_waddr == controller->size - 1)
541
            {
542
              controller->eeprom[controller->eeprom_waddr] = 0xff;
543
            }
544
          else if (cpu->ios[M6811_BYTE] & M6811_ROW)
545
            {
546
              size_t max_size;
547
 
548
              /* Size of EEPROM (-1 because the last byte is the
549
                 CONFIG register.  */
550
              max_size = controller->size;
551
              controller->eeprom_waddr &= 0xFFF0;
552
              for (i = 0; i < 16
553
                     && controller->eeprom_waddr < max_size; i++)
554
                {
555
                  controller->eeprom[controller->eeprom_waddr] = 0xff;
556
                  controller->eeprom_waddr ++;
557
                }
558
            }
559
          else
560
            {
561
              size_t max_size;
562
 
563
              max_size = controller->size;
564
              for (i = 0; i < max_size; i++)
565
                {
566
                  controller->eeprom[i] = 0xff;
567
                }
568
            }
569
 
570
          /* Save the eeprom in a file.  We have to save after each
571
             change because the simulator can be stopped or crash...  */
572
          if (m6811eepr_memory_rw (controller, O_WRONLY | O_CREAT) != 0)
573
            {
574
              sim_memory_error (cpu, SIM_SIGABRT, addr,
575
                                "EEPROM programing failed: errno=%d", errno);
576
            }
577
          controller->eeprom_wmode = 0;
578
        }
579
      cpu->ios[M6811_PPROG] = val;
580
      return 1;
581
    }
582
 
583
  /* The CONFIG IO register is mapped at end of EEPROM.
584
     It's not visible.  */
585
  if (space == io_map && base == M6811_CONFIG)
586
    {
587
      base = controller->size - 1;
588
    }
589
  else
590
    {
591
      base = base - controller->base_address;
592
    }
593
 
594
  /* Writing the memory is allowed for the Debugger or simulator
595
     (cpu not running).  */
596
  if (cpu_is_running (cpu))
597
    {
598
      if ((cpu->ios[M6811_PPROG] & M6811_EELAT) == 0)
599
        {
600
          sim_memory_error (cpu, SIM_SIGSEGV, base,
601
                            "EEprom not configured for writing");
602
          return 0;
603
        }
604
      if (controller->eeprom_wmode != 0)
605
        {
606
          sim_memory_error (cpu, SIM_SIGSEGV, base,
607
                            "EEprom write error");
608
          return 0;
609
        }
610
      controller->eeprom_wmode = 1;
611
      controller->eeprom_waddr = base;
612
      controller->eeprom_wbyte = val;
613
    }
614
  else
615
    {
616
      controller->eeprom[base] = val;
617
      m6811eepr_memory_rw (controller, O_WRONLY);
618
    }
619
 
620
  return 1;
621
}
622
 
623
const struct hw_descriptor dv_m68hc11eepr_descriptor[] = {
624
  { "m68hc11eepr", m68hc11eepr_finish },
625
  { "m68hc12eepr", m68hc11eepr_finish },
626
  { NULL },
627
};
628
 

powered by: WebSVN 2.1.0

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