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