OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / memory / at29.cxx
1 // at29.cxx - Implementation of ATMEL'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 "config.h"
8 #include "at29.h"
9 #include <new>
10
11 enum {
12   SEQ_ADDR1 = 0x5555,
13   SEQ_ADDR2 = 0xAAAA,
14   START_CMD1 = 0xAA,
15   START_CMD2 = 0x55,
16   ID_CMD = 0x90,
17   PROG_CMD = 0xA0,
18   STOP_CMD = 0xF0
19 };
20
21
22 at29_flash_memory::at29_flash_memory (size_t ms, size_t ss, host_int_1 id) throw (bad_alloc)
23   :my_bus(this),
24    state(LOCKED),
25    noSectorNum(0xFFFFFFFF),
26    sectorNum(noSectorNum),
27    manufacturerCode(0x1F)
28 {
29   // set incoming parameters
30   deviceIdCode = id;
31   sector_size = ss;
32   bool ok = attempt_resize (ms);
33   if (! ok)
34     throw bad_alloc (); // abort constructor
35
36   add_bus("read-write-port", &this->my_bus);
37   add_attribute("device-code", &deviceIdCode, "setting");
38   add_attribute_ro("manufacturer-code", &manufacturerCode, "setting");
39 }
40
41 void
42 at29_flash_memory::stream_state (ostream& out) const
43 {
44   flash_uniform_sector_memory::stream_state(out);
45   if (!out.good())
46     return;
47
48   out << ':' << "device-code " << deviceIdCode;
49 }
50
51 void
52 at29_flash_memory::destream_state (istream& in)
53 {
54   flash_uniform_sector_memory::destream_state(in);
55   if (!in.good())
56     return;
57
58   char ch;
59   string key;
60
61   in.get(ch);
62   if (ch != ':')
63     {
64       in.setstate(ios::badbit);
65       return;
66     }
67   in >> key;
68   if (key != "device-code")
69     {
70       in.setstate(ios::badbit);
71       return;
72     }
73   in >> deviceIdCode;
74 }
75
76 bool
77 at29_flash_memory::write_ok(host_int_4 address)
78 {
79   if (sectorNum == noSectorNum)
80     {
81       sectorNum = address / sector_size;
82     }
83   else
84     {
85       if (sectorNum != address / sector_size)
86         {
87           return false;
88         }
89     }
90   return (state == PROG);
91 }
92
93
94 bus::status
95 at29_bus::read(host_int_4 address,
96                little_int_1& data) throw ()
97 {
98   if (target->state == at29_flash_memory::IDENT)
99     {
100       switch (address) {
101       case 0:
102         data = target->manufacturerCode;
103         return bus::ok;
104       case 1:
105         data = target->deviceIdCode;
106         return bus::ok;
107       default:
108         return bus::unpermitted;
109       }
110     }
111   
112   // Bounds check the memory read.
113   if (address > target->buffer_length)
114     {
115       return bus::unmapped;
116     }
117   data = target->buffer[address];
118   return bus::ok;
119 }
120
121
122 bus::status
123 at29_bus::read(host_int_4 address,
124                big_int_1& data) throw ()
125 {
126   little_int_1 littleData(data);
127   
128   bus::status result = read(address, littleData);
129   data = littleData;
130   
131   return result;
132 }       
133
134
135 bus::status
136 at29_bus::write(host_int_4 address, 
137                 little_int_1 le_data) throw()
138 {
139   host_int_1 data = le_data;
140
141   if (target->state == at29_flash_memory::PROG &&
142       address == SEQ_ADDR1 && data == START_CMD1)
143     {
144       target->state = at29_flash_memory::LOCKED;
145     }
146   
147   if (target->state == at29_flash_memory::IDENT &&
148       address == SEQ_ADDR1 && data == START_CMD1)
149     {
150       target->state = at29_flash_memory::START1;
151       return bus::ok;
152     }
153   
154   if (target->state == at29_flash_memory::LOCKED &&
155       address == SEQ_ADDR1 && data == START_CMD1)
156     {
157       target->state = at29_flash_memory::START1;
158       return bus::ok;
159     }
160   
161   if (target->state == at29_flash_memory::START1 &&
162       address == SEQ_ADDR2 && data == START_CMD2)
163     {
164       target->state = at29_flash_memory::START2;
165       return bus::ok;
166     }
167   
168   if (target->state == at29_flash_memory::START2 &&
169       address == SEQ_ADDR1 && data == ID_CMD)
170     {
171       target->state = at29_flash_memory::IDENT;
172       return bus::ok;
173     }
174   
175   if (target->state == at29_flash_memory::START2 &&
176       address == SEQ_ADDR1 && data == STOP_CMD)
177     {
178       target->state = at29_flash_memory::LOCKED;
179       return bus::ok;
180     }
181   
182   if (target->state == at29_flash_memory::START2 &&
183       address == SEQ_ADDR1 && data == PROG_CMD)
184     {
185       target->state = at29_flash_memory::PROG;
186       target->sectorNum = target->noSectorNum;
187       return bus::ok;
188     }
189   
190   // Bounds check the memory write.
191   if (address > target->buffer_length)
192     {
193       return bus::unmapped;
194     }
195   
196   if (target->write_ok(address))
197     {
198       target->buffer[address] = data;
199     }
200
201   return bus::ok;
202 }
203
204
205 bus::status
206 at29_bus::write(host_int_4 address,
207                 big_int_1 data) throw ()
208 {
209   return write(address, little_int_1(data));
210 }
211
212
213 // static const description table for flash family
214 // Details taken from Atmel Flash Application Note AN-3, Rev. 0518B-10/98.
215
216 const at29_flash_memory_type at29_flash_memory::types[] = 
217 {
218   { "c256",   32*1024,  64,  0xDC },
219   { "lv256",  32*1024,  64,  0xBC },
220   { "c257",   32*1024,  64,  0xDC },
221   { "c512",   64*1024,  128, 0x5D },
222   { "lv512",  64*1024,  128, 0x3D },
223   { "c010a",  128*1024, 128, 0xD5 },
224   { "lv010a", 128*1024, 128, 0x35 },
225   { "bv010a", 128*1024, 128, 0x35 },
226   // at29c1024 and at29lv1024 are 16-bit-wide devices, not supported by this code
227   { "c020",   256*1024, 256, 0xDA },
228   { "lv020",  256*1024, 256, 0xBA },
229   { "bv020",  256*1024, 256, 0xBA },
230   { "c040",   512*1024, 512, 0x5B },
231   { "lv040",  512*1024, 512, 0x3B },
232   { "bv040",  512*1024, 512, 0x3B },
233   { "c040a",  512*1024, 256, 0xA4 },
234   { "lv040a", 512*1024, 256, 0xC4 },
235   { "bv040a", 512*1024, 256, 0xC4 },
236   // termination
237   { 0, 0, 0, 0 }
238 };