yaffs Moving timothy_tests and updating the makefiles to work with the new test-framework
[yaffs2.git] / direct / test-framework / ynorsim.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2011 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include "ynorsim.h"
15
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <time.h>
21
22 #define YNORSIM_FNAME "emfile-nor"
23
24 /* Set YNORSIM_BIT_CHANGES to a a value from 1..30 to
25  *simulate bit flipping as the programming happens.
26  * A low value results in faster simulation with less chance of encountering a partially programmed
27  * word.
28  */
29
30 //#define YNORSIM_BIT_CHANGES 15
31 #define YNORSIM_BIT_CHANGES 2
32
33 #if 0
34 /* Simulate 32MB of flash in 256k byte blocks.
35  * This stuff is x32.
36  */
37
38 #define YNORSIM_BLOCK_SIZE_U32  (256*1024/4)
39 #define YNORSIM_DEV_SIZE_U32    (32*1024 * 1024/4)
40 #else
41 /* Simulate 8MB of flash in 256k byte blocks.
42  * This stuff is x32.
43  */
44
45 #define YNORSIM_BLOCK_SIZE_U32  (256*1024/4)
46 #define YNORSIM_DEV_SIZE_U32    (8*1024 * 1024/4)
47 #endif
48
49 struct nor_sim {
50         int n_blocks;
51         int block_size_bytes;
52         int file_size;
53         u32 *word;
54         int initialised;
55         char *fname;
56         int remaining_ops;
57         int nops_so_far;
58 };
59
60 int ops_multiplier = 500;
61 extern int random_seed;
62 extern int simulate_power_failure;
63
64 static void NorError(struct nor_sim *sim)
65 {
66         printf("Nor error on device %s\n", sim->fname);
67         while (1) {
68         }
69 }
70
71 static void ynorsim_save_image(struct nor_sim *sim)
72 {
73         int h;
74
75         h = open(sim->fname, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
76         write(h, sim->word, sim->file_size);
77         close(h);
78 }
79
80 static void ynorsim_restore_image(struct nor_sim *sim)
81 {
82         int h;
83
84         h = open(sim->fname, O_RDONLY, S_IREAD | S_IWRITE);
85         memset(sim->word, 0xFF, sim->file_size);
86         read(h, sim->word, sim->file_size);
87         close(h);
88 }
89
90 static void ynorsim_power_fail(struct nor_sim *sim)
91 {
92         ynorsim_save_image(sim);
93         exit(1);
94 }
95
96 static void ynorsim_maybe_power_fail(struct nor_sim *sim)
97 {
98         sim->nops_so_far++;
99         sim->remaining_ops--;
100         if (simulate_power_failure && sim->remaining_ops < 1) {
101                 printf("Simulated power failure after %d operations\n",
102                        sim->nops_so_far);
103                 ynorsim_power_fail(sim);
104         }
105 }
106
107 static void ynorsim_ready(struct nor_sim *sim)
108 {
109         if (sim->initialised)
110                 return;
111         srand(random_seed);
112         sim->remaining_ops = 1000000000;
113         sim->remaining_ops =
114             (rand() % 10000) * ops_multiplier * YNORSIM_BIT_CHANGES;
115         ynorsim_restore_image(sim);
116         sim->initialised = 1;
117 }
118
119 /* Public functions. */
120
121 void ynorsim_rd32(struct nor_sim *sim, u32 * addr, u32 * buf, int nwords)
122 {
123         sim = sim;
124         while (nwords > 0) {
125                 *buf = *addr;
126                 buf++;
127                 addr++;
128                 nwords--;
129         }
130 }
131
132 void ynorsim_wr_one_word32(struct nor_sim *sim, u32 * addr, u32 val)
133 {
134         u32 tmp;
135         u32 m;
136         int i;
137
138         tmp = *addr;
139         if (val & ~tmp) {
140                 /* Fail due to trying to change a zero into a 1 */
141                 printf("attempt to set a zero to one (%x)->(%x)\n", tmp, val);
142                 NorError(sim);
143         }
144
145         for (i = 0; i < YNORSIM_BIT_CHANGES; i++) {
146                 m = 1 << (rand() & 31);
147                 if (!(m & val)) {
148                         tmp &= ~m;
149                         *addr = tmp;
150                         ynorsim_maybe_power_fail(sim);
151                 }
152
153         }
154
155         *addr = tmp & val;
156         ynorsim_maybe_power_fail(sim);
157 }
158
159 void ynorsim_wr32(struct nor_sim *sim, u32 * addr, u32 * buf, int nwords)
160 {
161         while (nwords > 0) {
162                 ynorsim_wr_one_word32(sim, addr, *buf);
163                 addr++;
164                 buf++;
165                 nwords--;
166         }
167 }
168
169 void ynorsim_erase(struct nor_sim *sim, u32 * addr)
170 {
171         /* Todo... bit flipping */
172         memset(addr, 0xFF, sim->block_size_bytes);
173 }
174
175 struct nor_sim *ynorsim_initialise(char *name, int n_blocks,
176                                    int block_size_bytes)
177 {
178         struct nor_sim *sim;
179
180         sim = malloc(sizeof(*sim));
181         if (!sim)
182                 return NULL;
183
184         memset(sim, 0, sizeof(*sim));
185         sim->n_blocks = n_blocks;
186         sim->block_size_bytes = block_size_bytes;
187         sim->file_size = n_blocks * block_size_bytes;
188         sim->word = malloc(sim->file_size);
189         sim->fname = strdup(name);
190
191         if(!sim->word)
192                 return NULL;
193
194         ynorsim_ready(sim);
195         return sim;
196 }
197
198 void ynorsim_shutdown(struct nor_sim *sim)
199 {
200         ynorsim_save_image(sim);
201         sim->initialised = 0;
202 }
203
204 u32 *ynorsim_get_base(struct nor_sim *sim)
205 {
206         return sim->word;
207 }