]> Git Repo - binutils.git/blob - sim/ppc/hw_eeprom.c
update from Andrew
[binutils.git] / sim / ppc / hw_eeprom.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1996, Andrew Cagney <[email protected]>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  
19     */
20
21
22 #ifndef _HW_EEPROM_C_
23 #define _HW_EEPROM_C_
24
25 #ifndef STATIC_INLINE_HW_EEPROM
26 #define STATIC_INLINE_HW_EEPROM STATIC_INLINE
27 #endif
28
29 #include "device_table.h"
30
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #else
34 #ifdef HAVE_STRINGS_H
35 #include <strings.h>
36 #endif
37 #endif
38
39 /* EEPROM - electricaly erasable programable memory
40
41    Description:
42
43    This device implements a small byte addressable EEPROM.
44    Programming is performed using the same write sequences as used by
45    modern EEPROM components.  Writes occure in real time, the device
46    returning a progress value until the programing has been completed.
47
48    Properties:
49
50    reg = <address> <size>.  Determine where the device lives in the
51    parents address space.
52
53    nr-sectors = <integer>.  When erasing an entire sector is cleared
54    at a time.  This specifies the number of sectors in the EEPROM
55    component.
56
57    byte-write-delay = <integer>.  Number of clock ticks before the
58    programming of a single byte completes.
59
60    sector-start-delay = <integer>.  When erasing sectors, the number
61    of clock ticks after the sector has been specified and the actual
62    erase process commences.
63
64    erase-delay = <intger>.  Number of clock ticks before an erase
65    program completes. */
66
67 typedef enum {
68   read_reset,
69   write_nr_2,
70   write_nr_3,
71   write_nr_4,
72   write_nr_5,
73   write_nr_6,
74   byte_program,
75   byte_programming,
76   chip_erase, chip_erasing,
77   sector_erase, sector_erasing,
78   sector_erase_suspend,
79   sector_erase_resume,
80 } eeprom_states;
81
82 typedef struct _eeprom_device {
83   unsigned8 *memory;
84   unsigned sizeof_memory;
85   unsigned sector_size;
86   unsigned nr_sectors;
87   unsigned byte_write_delay;
88   unsigned sector_start_delay;
89   unsigned erase_delay;
90   signed64 programme_start_time;
91   unsigned program_byte_address;
92   eeprom_states state;
93 } eeprom_device;
94
95 static void *
96 eeprom_create(const char *name,
97              const device_unit *unit_address,
98              const char *args,
99              device *parent)
100 {
101   eeprom_device *eeprom = ZALLOC(eeprom_device);
102   return eeprom;
103 }
104
105 typedef struct _eeprom_reg_spec {
106   unsigned32 base;
107   unsigned32 size;
108 } eeprom_reg_spec;
109
110 static void
111 eeprom_init_address(device *me,
112                    psim *system)
113 {
114   eeprom_device *eeprom = (eeprom_device*)device_data(me);
115   const device_property *reg = device_find_array_property(me, "reg");
116   const eeprom_reg_spec *spec = reg->array;
117   int nr_entries = reg->sizeof_array / sizeof(*spec);
118
119   if ((reg->sizeof_array % sizeof(*spec)) != 0)
120     error("devices/%s reg property of incorrect size\n", device_name(me));
121   if (nr_entries > 1)
122     error("devices/%s reg property contains multiple specs\n",
123           device_name(me));
124
125   /* initialize the eeprom */
126   if (eeprom->memory == NULL) {
127     eeprom->sizeof_memory = BE2H_4(spec->size);
128     eeprom->memory = zalloc(eeprom->sizeof_memory);
129   }
130   else
131     memset(eeprom->memory, eeprom->sizeof_memory, 0);
132
133   /* figure out the sectors in the eeprom */
134   eeprom->nr_sectors = device_find_integer_property(me, "nr-sectors");
135   eeprom->sector_size = eeprom->sizeof_memory / eeprom->nr_sectors;
136   if (eeprom->sector_size * eeprom->nr_sectors != eeprom->sizeof_memory)
137     error("device/%s nr-sectors does not evenly divide eeprom\n",
138           device_name(me));
139
140   /* timing */
141   eeprom->byte_write_delay = device_find_integer_property(me, "byte-write-delay");
142   eeprom->sector_start_delay = device_find_integer_property(me, "sector-start-delay");
143   eeprom->erase_delay = device_find_integer_property(me, "erase-delay");
144
145   device_attach_address(device_parent(me),
146                         device_name(me),
147                         attach_callback,
148                         0 /*address space*/,
149                         BE2H_4(spec->base),
150                         eeprom->sizeof_memory,
151                         access_read_write_exec,
152                         me);
153 }
154
155
156 static unsigned
157 eeprom_io_read_buffer(device *me,
158                       void *dest,
159                       int space,
160                       unsigned_word addr,
161                       unsigned nr_bytes,
162                       cpu *processor,
163                       unsigned_word cia)
164 {
165   eeprom_device *eeprom = (eeprom_device*)device_data(me);
166   int i;
167   for (i = 0; i < nr_bytes; i++) {
168     unsigned_word address = (addr + nr_bytes) % eeprom->sizeof_memory;
169     eeprom->memory[address] = eeprom_io_read_byte(address);
170   }
171   return nr_bytes;
172 }
173
174 static void
175 eeprom_io_write_byte()
176 {
177   switch (state) {
178   case read_reset:
179     if (address == 0x5555 && data = 0xaa)
180       state = first_write;
181     else
182       state = read_reset;
183     break;
184   case first_write:
185     if (address == 0x2aaa && data == 0x55)
186       state = second_write;
187     else
188       state = read_reset; /* issue warning */
189     break;
190   case second_write:
191     if (address == 0x5555 && data == 0xf0)
192       state = read_reset;
193     else if (address == 0x5555 && data == 0x90)
194       state = auto_select;
195     else if (address == 0x5555 && data == 0xa0)
196       state = byte_program;
197     else if (address == 0x5555 && data == 0x80)
198       state = third_write;
199     else
200       state = read_reset;
201     break;
202   case fourth_write:
203     if (address == 0x5555 && data == 0xaa)
204       state = fith_write;
205     else
206       state = read_reset;
207     break;
208   case fith_write:
209     if (address == 0x2aaa && data == 0x55)
210       state = sixth_write;
211     else
212       state = read_reset;
213     break;
214   case sixth_write:
215     if (address == 0x5555 && data == 0x10)
216       state = chip_erase;
217     else
218       sector_erase();
219     break;
220   case auto_select:
221     if (data == 0xf0)
222       state = read_reset;
223     else if (address == 0x5555 && data == 0xaa)
224       state = second_write;
225     else
226       state = read_reset; /* issue warning */
227     break;
228   case sector_erase:
229     if (data == 0xb0)
230       state = sector_erase_suspend;
231     else
232       state = sector_erase; /* ignore */
233     break;
234   case sector_erase_suspend:
235     if (data == 0x30)
236       state = sector_erase;
237     else
238       state = sector_erase_suspend; /* ignore */
239     break;
240   case byte_program:
241     /* perform the byte program */
242     program_address = address;
243     program_start = some_time();
244     toggle = 0;
245     /* but only make things `0' and never 1 */
246     byte[address] = data;
247     state = byte_programming;
248     break;
249   case byte_programming:
250     if (finished)
251       state = read_reset;
252     else
253       state = byte_programming;
254     break;
255   }
256 }
257
258 static unsigned
259 eeprom_io_write_buffer(device *me,
260                        const void *source,
261                        int space,
262                        unsigned_word addr,
263                        unsigned nr_bytes,
264                        cpu *processor,
265                        unsigned_word cia)
266 {
267   eeprom_device *eeprom = (eeprom_device*)device_data(me);
268   int i;
269   for (i = 0; i < nr_bytes; i++) {
270     unsigned_word address = (addr + nr_bytes) % eeprom->sizeof_memory;
271     eeprom_io_read_byte(address, eeprom->memory[address]);
272   }
273   return nr_bytes;
274 }
275
276
277
278 static device_callbacks const eeprom_callbacks = {
279   { eeprom_init_address, },
280   { NULL, }, /* address */
281   { eeprom_io_read_buffer, eeprom_io_write_buffer }, /* IO */
282 };
283
284 const device_descriptor eeprom_device_descriptor[] = {
285   { "eeprom", eeprom_create, &eeprom_callbacks },
286   { NULL },
287 };
288
289 #endif /* _HW_EEPROM_C_ */
This page took 0.040112 seconds and 4 git commands to generate.