OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / memory / am29.cxx
1 // am29.cxx - Implementation of AMD's 29xxx flash memory.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 #include <sidcomp.h>
8 #include <sidbusutil.h>
9
10 #include "am29.h"
11
12 enum {
13   STATE_READ,
14   STATE_UNLOCK1,
15   STATE_UNLOCK2,
16   STATE_AUTOSELECT,
17   STATE_PROGRAM,
18   STATE_ERASE0,
19   STATE_ERASE1,
20   STATE_ERASE2,
21   STATE_BYPASS,
22   STATE_BYPASS_RESET
23 };
24
25 enum {
26   UNLOCK = 0x555,
27   UNLOCK2 = 0x2AA
28 };
29
30 enum {
31   AUTOSELECT_CMD = 0x90,
32   ERASE_CMD = 0x80,
33   ERASE_CHIP_CMD = 0x10,
34   ERASE_SECTOR_CMD = 0x30,
35   PROGRAM_CMD = 0xA0,
36   UNLOCK1_CMD = 0xAA,
37   UNLOCK2_CMD = 0x55,
38   BYPASS_CMD = 0x20,
39   BYPASS_PROG_CMD = 0xA0,
40   BYPASS_RESET_CMD = 0x90
41 };
42  
43 am29_flash_memory::am29_flash_memory (size_t ms, size_t ss, host_int_1 id)
44   :my_bus(this),
45    manufacturerCode(0x01)
46 {
47   // set incoming parameters
48   deviceIdCode = id;
49   sector_size = ss;
50   if (!attempt_resize(ms))
51     {
52       throw bad_alloc();
53     }
54   
55   mode = STATE_READ;
56   erase();
57
58   add_bus("read-write-port", &this->my_bus);
59   add_attribute_ro("mode", &mode);
60   add_attribute("device-code", &deviceIdCode, "setting");
61   add_attribute_ro_value("manufacturer-code", manufacturerCode, "setting");
62 }
63
64 void
65 am29_flash_memory::stream_state (ostream& out) const
66 {
67   flash_uniform_sector_memory::stream_state(out);
68   if (!out.good())
69     return;
70
71   out << ':' << "device-code " << deviceIdCode;
72 }
73
74 void
75 am29_flash_memory::destream_state (istream& in)
76 {
77   flash_uniform_sector_memory::destream_state(in);
78   if (!in.good())
79     return;
80
81   char ch;
82   string key;
83
84   in.get(ch);
85   if (ch != ':')
86     {
87       in.setstate(ios::badbit);
88       return;
89     }
90   in >> key;
91   if (key != "device-code")
92     {
93       in.setstate(ios::badbit);
94       return;
95     }
96   in >> deviceIdCode;
97 }
98
99
100 // Erase the entire chip.
101 void
102 am29_flash_memory::erase()
103 {
104   for (unsigned i = 0; i < buffer_length; i++)
105     {
106      buffer[i] = 0xFF;
107     }
108 }
109
110 // Erase a sector.
111 void
112 am29_flash_memory::erase(unsigned sector)
113 {
114   host_int_4 start_addr = sector_size * sector;
115
116   if (start_addr >= buffer_length)
117     return;
118
119   host_int_4 end_addr = sector_size * (sector + 1);
120
121   if (end_addr > buffer_length)
122     end_addr = buffer_length;
123   
124   assert(start_addr < end_addr);
125   assert(start_addr < buffer_length);
126   assert(end_addr < buffer_length);
127   
128   for (unsigned i = start_addr; i < end_addr; i++)
129     {
130       buffer[i] = 0xFF;
131     }
132 }
133
134
135 bool
136 am29_flash_memory::write_ok(host_int_4 address)
137 {
138   return (mode == STATE_PROGRAM);
139 }
140
141
142 bus::status
143 am29_flash_memory::am29_bus::read(host_int_4 address,
144                                   little_int_1& data) throw ()
145 {
146   try
147     {
148       if (target->mode == STATE_AUTOSELECT)
149         {
150           if ((address & 0xF) == 0)
151             data = target->manufacturerCode;
152           else if ((address & 0xF) == 1)
153             data = target->deviceIdCode;
154           else if ((address & 0xF) == 2)
155             {
156               // FIXME: All sectors are unprotected.
157               data = 0;
158             }
159           return bus::ok;
160         }
161
162       // Bounds check the memory reference.
163       if (address > target->buffer_length)
164         {
165           return bus::unmapped;
166         }
167       data = target->buffer[address];
168       return sid::bus::ok;
169     }
170   catch (...)
171     {
172       return sid::bus::delayed;
173     }
174 }
175  
176
177 bus::status
178 am29_flash_memory::am29_bus::read(host_int_4 address,
179                                   big_int_1& data) throw ()
180 {
181   try
182     {
183       little_int_1 littleData(data);
184       bus::status result = read(address, littleData);
185       data = littleData;
186       return result;
187     }
188   catch (...)
189     {
190       return sid::bus::delayed;
191     }
192 }       
193
194
195 bus::status
196 am29_flash_memory::am29_bus::write(host_int_4 address, 
197                                    little_int_1 le_data) throw()
198 {
199   try
200     {
201       host_int_1 data = le_data;
202       
203       switch (target->mode)
204         {
205         case STATE_READ:
206           if (address == UNLOCK && data == UNLOCK1_CMD)
207             {
208               target->mode = STATE_UNLOCK1;
209               return bus::ok;
210             }
211           return bus::unpermitted;
212
213         case STATE_AUTOSELECT:
214           // Don't care about the address bits for the reset command.
215           if (data == 0xF0)
216             {
217               target->mode = STATE_READ;
218               return bus::ok;
219             }
220           return bus::ok;
221
222         case STATE_BYPASS:
223           // Don't care about address bits for the bypass program cmd.
224           if (data == BYPASS_PROG_CMD)
225             target->mode = STATE_PROGRAM;
226           else if (data == BYPASS_RESET_CMD)
227             target->mode = STATE_BYPASS_RESET;
228           else
229             target->mode = STATE_READ;
230           return bus::ok;
231
232         case STATE_BYPASS_RESET:
233           // Go back to read mode unconditionally -- this is the
234           // expected behaviour even if the magic codes are wrong.
235           target->mode = STATE_READ;
236           return bus::ok;
237
238         case STATE_ERASE0:
239           if (address == UNLOCK && data == UNLOCK1_CMD)
240             target->mode = STATE_ERASE1;
241           else
242             target->mode = STATE_READ;
243           return bus::ok;
244
245         case STATE_ERASE1:
246           if (address == UNLOCK2 && data == UNLOCK2_CMD)
247             target->mode = STATE_ERASE2;
248           else
249             target->mode = STATE_READ;
250           return bus::ok;
251
252         case STATE_ERASE2:
253           if (address == UNLOCK && data == ERASE_CHIP_CMD)
254             {
255               target->erase();
256             }
257           else if (UNLOCK && data == ERASE_SECTOR_CMD)
258             {
259               target->erase((address >> 16));
260             }
261           target->mode = STATE_READ;
262           return bus::ok;
263           
264         case STATE_UNLOCK1:
265           if (address == UNLOCK2 && data == UNLOCK2_CMD)
266             target->mode = STATE_UNLOCK2;
267           else
268             target->mode = STATE_READ;
269           return bus::ok;
270           
271         case STATE_UNLOCK2:
272           if (address == UNLOCK && data == AUTOSELECT_CMD)
273             target->mode = STATE_AUTOSELECT;
274           else if (address == UNLOCK && data == PROGRAM_CMD)
275             target->mode = STATE_PROGRAM;
276           else if (address == UNLOCK && data == ERASE_CMD)
277             target->mode = STATE_ERASE0;
278           else if (address == UNLOCK && data == BYPASS_CMD)
279             target->mode = STATE_BYPASS;
280           else
281             target->mode = STATE_READ;
282           return bus::ok;
283         }
284
285       if (address > target->buffer_length)
286         {
287           return bus::unmapped;
288         }
289
290       if (target->write_ok(address))
291         {
292           little_int_1 old_data = target->buffer[address];
293           for (int i = 0; i < 8; i++)
294             {
295               int mask = 1 << i;
296               if (((old_data & mask) == 0) && ((data & mask) != 0))
297                 {
298                   // Cannot change a 0 back to a 1, so clear this bit.
299                   data &= ~mask;
300                 }
301             }
302                   
303           target->buffer[address] = data;
304           target->mode = STATE_READ;
305           return bus::ok;
306         }
307       else
308         return bus::delayed;
309     }
310   catch (...)
311     {
312       return bus::delayed;
313     }
314 }
315
316
317 bus::status
318 am29_flash_memory::am29_bus::write(host_int_4 address,
319                                    big_int_1 data) throw ()
320 {
321   return write(address, little_int_1(data));
322 }
323
324 // static const description table for flash family
325 // Details taken from AMD data sheet, publication no. 21354, 1999-05-18.
326
327 const am29_flash_memory_type am29_flash_memory::types[] = 
328 {
329   { "f010a", 128*1024, 16*1024, 0x20 },
330   { "lv010b", 128*1024, 16*1024, 0x6E },
331   { "lv040b", 512*1024, 64*1024, 0x4F },
332   { "lv081b", 1024*1024, 64*1024, 0x38 },
333   { "lv017b", 2*1024*1024, 64*1024, 0xC8 },
334   { "lv033c", 4*1024*1024, 64*1024, 0xA3 },
335   // termination
336   { 0, 0, 0, 0 }
337 };