1 //---------------------------------------------------------------------------
2 // NEOPOP : Emulator as in Dreamland
3 //
4 // Copyright (c) 2001-2002 by neopop_uk
5 //---------------------------------------------------------------------------
6
7 //---------------------------------------------------------------------------
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version. See also the license.txt file for
12 // additional informations.
13 //---------------------------------------------------------------------------
14
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "flash.h"
19 #include "mem.h"
20 #include "rom.h"
21 #include "system.h"
22
23 #include "../state.h"
24
25 //-----------------------------------------------------------------------------
26 // Local Definitions
27 //-----------------------------------------------------------------------------
28 //This value is used to verify flash data - it is set to the
29 //version number that the flash description was modified for.
30
31 #define FLASH_VALID_ID 0x0053
32
33 //Number of different flash blocks, this should be enough.
34
35 #define FLASH_MAX_BLOCKS 256
36
37 typedef struct
38 {
39 //Flash Id
40 uint16_t valid_flash_id; // = FLASH_VALID_ID
41
42 uint16_t block_count; //Number of flash data blocks
43
44 uint32_t total_file_length; // header + block[0 - block_count]
45
46 } FlashFileHeader;
47
48 typedef struct
49 {
50 uint32_t start_address; // 24 bit address
51 uint16_t data_length; // length of following data
52
53 //Followed by data_length bytes of the actual data.
54
55 } FlashFileBlockHeader;
56
57 /* Local Data */
58 static FlashFileBlockHeader blocks[256];
59 static uint16_t block_count;
60
flash_optimise_blocks(void)61 void flash_optimise_blocks(void)
62 {
63 int i, j;
64
65 // Bubble Sort by address
66 for (i = 0; i < block_count - 1; i++)
67 {
68 for (j = i+1; j < block_count; j++)
69 {
70 //Swap?
71 if (blocks[i].start_address > blocks[j].start_address)
72 {
73 uint16_t temp16;
74 uint32_t temp32 = blocks[i].start_address;
75
76 blocks[i].start_address = blocks[j].start_address;
77 blocks[j].start_address = temp32;
78
79 temp16 = blocks[i].data_length;
80 blocks[i].data_length = blocks[j].data_length;
81 blocks[j].data_length = temp16;
82 }
83 }
84 }
85
86 //Join contiguous blocks
87 //Only advance 'i' if required, this will allow subsequent
88 //blocks to be compared to the newly expanded block.
89 for (i = 0; i < block_count - 1; /**/)
90 {
91 //Next block lies within (or borders) this one?
92 if (blocks[i+1].start_address <=
93 (blocks[i].start_address + blocks[i].data_length))
94 {
95 //Extend the first block
96 blocks[i].data_length =
97 (uint16_t)((blocks[i+1].start_address + blocks[i+1].data_length) -
98 blocks[i].start_address);
99 //FIXME: std::max
100
101 //Remove the next one.
102 for (j = i+2; j < block_count; j++)
103 {
104 blocks[j-1].start_address = blocks[j].start_address;
105 blocks[j-1].data_length = blocks[j].data_length;
106 }
107 block_count --;
108 }
109 else
110 {
111 i++; // Try the next block
112 }
113 }
114 }
115
do_flash_read(uint8_t * flashdata)116 void do_flash_read(uint8_t *flashdata)
117 {
118 FlashFileHeader header;
119 uint8_t *fileptr;
120 uint16_t i;
121 uint32_t j;
122 bool PREV_memory_unlock_flash_write = memory_unlock_flash_write; // kludge, hack, FIXME
123
124 memcpy(&header, flashdata, sizeof(header));
125
126 //Read header
127 block_count = header.block_count;
128 fileptr = flashdata + sizeof(FlashFileHeader);
129
130 //Copy blocks
131 memory_unlock_flash_write = 1;
132 for (i = 0; i < block_count; i++)
133 {
134 FlashFileBlockHeader* current = (FlashFileBlockHeader*)fileptr;
135 fileptr += sizeof(FlashFileBlockHeader);
136
137 blocks[i].start_address = current->start_address;
138 blocks[i].data_length = current->data_length;
139
140 //Copy data
141 for (j = 0; j < blocks[i].data_length; j++)
142 {
143 storeB(blocks[i].start_address + j, *fileptr);
144 fileptr++;
145 }
146 }
147 memory_unlock_flash_write = PREV_memory_unlock_flash_write;
148
149 flash_optimise_blocks(); //Optimise
150
151
152 //Output block list...
153 /* for (i = 0; i < block_count; i++)
154 system_debug_message("flash block: %06X, %d bytes",
155 blocks[i].start_address, blocks[i].data_length);*/
156 }
157
flash_read(void)158 void flash_read(void)
159 {
160 FlashFileHeader header;
161 uint8_t* flashdata;
162
163 //Initialise the internal flash configuration
164 block_count = 0;
165
166 header.valid_flash_id = 0;
167 header.block_count = 0;
168 header.total_file_length = 0;
169
170 //Read flash buffer header
171 if (system_io_flash_read((uint8_t*)&header, sizeof(FlashFileHeader)) == 0)
172 return; //Silent failure - no flash data yet.
173
174 //Verify correct flash id
175 if (header.valid_flash_id != FLASH_VALID_ID)
176 return;
177
178 //Read the flash data
179 flashdata = (uint8_t*)malloc(header.total_file_length * sizeof(uint8_t));
180 system_io_flash_read(flashdata, header.total_file_length);
181
182 do_flash_read(flashdata);
183
184 free(flashdata);
185 }
186
flash_write(uint32_t start_address,uint16_t length)187 void flash_write(uint32_t start_address, uint16_t length)
188 {
189 uint16_t i;
190
191 //Now we need a new flash command before the next flash write will work!
192 memory_flash_command = 0;
193
194 // system_debug_message("flash write: %06X, %d bytes", start_address, length);
195
196 for (i = 0; i < block_count; i++)
197 {
198 //Got this block with enough bytes to cover it
199 if (blocks[i].start_address == start_address &&
200 blocks[i].data_length >= length)
201 return; //Nothing to do, block already registered.
202
203 //Got this block with but it's length is too short
204 if (blocks[i].start_address == start_address &&
205 blocks[i].data_length < length)
206 {
207 blocks[i].data_length = length; //Enlarge block updating.
208 return;
209 }
210 }
211
212 // New block needs to be added
213 blocks[block_count].start_address = start_address;
214 blocks[block_count].data_length = length;
215 block_count++;
216 }
217
make_flash_commit(int32_t * length)218 uint8_t *make_flash_commit(int32_t *length)
219 {
220 int i;
221 FlashFileHeader header;
222 uint8_t *flashdata, *fileptr;
223
224 /* No flash data? */
225 if (block_count == 0)
226 return NULL;
227
228 /* Optimize before writing */
229 flash_optimise_blocks();
230
231 /* Build a header */
232 header.valid_flash_id = FLASH_VALID_ID;
233 header.block_count = block_count;
234 header.total_file_length = sizeof(FlashFileHeader);
235
236 for (i = 0; i < block_count; i++)
237 {
238 header.total_file_length += sizeof(FlashFileBlockHeader);
239 header.total_file_length += blocks[i].data_length;
240 }
241
242 /* Write the flash data */
243 flashdata = (uint8_t*)malloc(header.total_file_length * sizeof(uint8_t));
244
245 /* Copy header */
246 memcpy(flashdata, &header, sizeof(FlashFileHeader));
247 fileptr = flashdata + sizeof(FlashFileHeader);
248
249 /* Copy blocks */
250 for (i = 0; i < block_count; i++)
251 {
252 uint32_t j;
253
254 memcpy(fileptr, &blocks[i], sizeof(FlashFileBlockHeader));
255 fileptr += sizeof(FlashFileBlockHeader);
256
257 /* Copy data */
258 for (j = 0; j < blocks[i].data_length; j++)
259 {
260 *fileptr = loadB(blocks[i].start_address + j);
261 fileptr++;
262 }
263 }
264
265 *length = header.total_file_length;
266 return flashdata;
267 }
268
flash_commit(void)269 void flash_commit(void)
270 {
271 int32_t length = 0;
272 uint8_t *flashdata = make_flash_commit(&length);
273
274 if (!flashdata)
275 return;
276
277 system_io_flash_write(flashdata, length);
278 free(flashdata);
279 }
280