yaffs Refactor yaffs direct device list management, add nand abstraction, divide...
[yaffs2.git] / direct / basic-test / yramsim.c
diff --git a/direct/basic-test/yramsim.c b/direct/basic-test/yramsim.c
new file mode 100644 (file)
index 0000000..a791791
--- /dev/null
@@ -0,0 +1,277 @@
+// NAND Simulator for testing YAFFS\r
+\r
+#include <string.h>\r
+\r
+#include "yramsim.h"\r
+\r
+#include "yaffs_nandif.h"\r
+\r
+\r
+#ifdef __WINCE__\r
+#include <windows.h>\r
+#else\r
+#define DebugBreak() do { } while(0)\r
+#endif\r
+\r
+\r
+#define DATA_SIZE      2048\r
+#define SPARE_SIZE     64\r
+#define PAGE_SIZE      (DATA_SIZE + SPARE_SIZE)\r
+#define PAGES_PER_BLOCK        64\r
+\r
+\r
+typedef struct {\r
+       unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];\r
+       unsigned blockOk;\r
+} Block;\r
+\r
+typedef struct {\r
+       Block **blockList;\r
+       int nBlocks;\r
+} SymData;\r
+\r
+\r
+static SymData *DevToSym(yaffs_Device *dev)\r
+{\r
+       ynandif_Geometry *geom = (ynandif_Geometry *)(dev->driverContext);\r
+       SymData * sym = (SymData*)(geom->privateData);\r
+       return sym;\r
+} \r
+\r
+\r
+static void CheckInitialised(void)\r
+{\r
+\r
+}\r
+\r
+static int yramsim_EraseBlockInternal(SymData *sym, unsigned blockId,int force)\r
+{\r
+       if(blockId < 0 || blockId >= sym->nBlocks){\r
+               DebugBreak();\r
+               return 0;\r
+       }\r
+\r
+       if(!sym->blockList[blockId]){\r
+               DebugBreak();\r
+               return 0;\r
+       }\r
+\r
+       if(!force && !sym->blockList[blockId]->blockOk){\r
+               DebugBreak();\r
+               return 0;\r
+       }\r
+\r
+       memset(sym->blockList[blockId],0xff,sizeof(Block));\r
+       sym->blockList[blockId]->blockOk = 1;\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+\r
+static int yramsim_Initialise(yaffs_Device *dev)\r
+{\r
+       SymData *sym = DevToSym(dev);\r
+       Block **blockList = sym->blockList;\r
+       return blockList != NULL;\r
+}\r
+\r
+\r
+static int yramsim_Deinitialise(yaffs_Device *dev)\r
+{\r
+       return 1;\r
+}\r
+\r
+static int yramsim_ReadChunk (yaffs_Device *dev, unsigned pageId, \r
+                                         unsigned char *data, unsigned dataLength,\r
+                                         unsigned char *spare, unsigned spareLength,\r
+                                         int *eccStatus)\r
+{\r
+       SymData *sym = DevToSym(dev);\r
+       Block **blockList = sym->blockList;\r
+\r
+       unsigned blockId = pageId / PAGES_PER_BLOCK;\r
+       unsigned pageOffset = pageId % PAGES_PER_BLOCK;\r
+       unsigned char * d;\r
+       unsigned char *s;\r
+       if(blockId >= sym->nBlocks ||\r
+          pageOffset >= PAGES_PER_BLOCK ||\r
+          dataLength >DATA_SIZE ||\r
+          spareLength > SPARE_SIZE ||\r
+          !eccStatus ||\r
+          !blockList[blockId]->blockOk){\r
+                  DebugBreak();\r
+                  return 0;\r
+       }\r
+\r
+       d = blockList[blockId]->page[pageOffset];\r
+       s = d + DATA_SIZE;\r
+\r
+       if(data)\r
+               memcpy(data,d,dataLength);\r
+\r
+       if(spare)\r
+               memcpy(spare,s,spareLength);\r
+\r
+       *eccStatus = 0; // 0 = no error, -1 = unfixable error, 1 = fixable\r
+\r
+       return 1;\r
+       \r
+}\r
+\r
+static int yramsim_WriteChunk (yaffs_Device *dev,unsigned pageId, \r
+                                          const unsigned char *data, unsigned dataLength,\r
+                                          const unsigned char *spare, unsigned spareLength)\r
+{\r
+       SymData *sym = DevToSym(dev);\r
+       Block **blockList = sym->blockList;\r
+\r
+       unsigned blockId = pageId / PAGES_PER_BLOCK;\r
+       unsigned pageOffset = pageId % PAGES_PER_BLOCK;\r
+       unsigned char * d;\r
+       unsigned char *s;\r
+       if(blockId >= sym->nBlocks ||\r
+          pageOffset >= PAGES_PER_BLOCK ||\r
+          dataLength >DATA_SIZE ||\r
+          spareLength > SPARE_SIZE ||\r
+          !blockList[blockId]->blockOk){\r
+                  DebugBreak();\r
+                  return 0;\r
+       }\r
+\r
+       d = blockList[blockId]->page[pageOffset];\r
+       s = d + DATA_SIZE;\r
+\r
+       if(data)\r
+               memcpy(d,data,dataLength);\r
+\r
+       if(spare)\r
+               memcpy(s,spare,spareLength);\r
+\r
+       return 1;\r
+       \r
+}\r
+\r
+\r
+static int yramsim_EraseBlock(yaffs_Device *dev,unsigned blockId)\r
+{\r
+       SymData *sym = DevToSym(dev);\r
+\r
+       CheckInitialised();\r
+       return yramsim_EraseBlockInternal(sym,blockId,0);\r
+}\r
+\r
+static int yramsim_CheckBlockOk(yaffs_Device *dev,unsigned blockId)\r
+{\r
+       SymData *sym = DevToSym(dev);\r
+       Block **blockList = sym->blockList;\r
+       if(blockId >= sym->nBlocks){\r
+               DebugBreak();\r
+               return 0;\r
+       }\r
+\r
+       return blockList[blockId]->blockOk ? 1 : 0;\r
+}\r
+\r
+static int yramsim_MarkBlockBad(yaffs_Device *dev,unsigned blockId)\r
+{\r
+       SymData *sym = DevToSym(dev);\r
+       Block **blockList = sym->blockList;\r
+       if(blockId >= sym->nBlocks){\r
+               DebugBreak();\r
+               return 0;\r
+       }\r
+\r
+       blockList[blockId]->blockOk = 0;\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+static SymData *yramsim_AllocSymData(int nBlocks)\r
+{\r
+       int ok = 1;\r
+\r
+       Block **blockList;\r
+       SymData *sym;\r
+       Block *b;\r
+       int i;\r
+\r
+       sym = malloc(sizeof (SymData));\r
+       if(!sym)\r
+               return NULL;\r
+\r
+       blockList = malloc(nBlocks * sizeof(Block *));\r
+       \r
+       sym->blockList = blockList;\r
+       sym->nBlocks = nBlocks;\r
+       if(!blockList){\r
+               free(sym);\r
+               return NULL;\r
+       }\r
+\r
+       for(i = 0; i < nBlocks; i++)\r
+               blockList[i] = NULL;\r
+\r
+       for(i = 0; i < nBlocks && ok; i++){\r
+               b=  malloc(sizeof(Block));\r
+               if(b){\r
+                       blockList[i] = b;\r
+                       yramsim_EraseBlockInternal(sym,i,1);\r
+               }\r
+               else\r
+                       ok = 0;\r
+       }\r
+\r
+       if(!ok){\r
+               for(i = 0; i < nBlocks; i++)\r
+                       if(blockList[i]){\r
+                               free(blockList[i]);\r
+                               blockList[i] = NULL;\r
+                       }\r
+               free(blockList);\r
+               blockList = NULL;\r
+               free(sym);\r
+               sym = NULL;\r
+       }\r
+\r
+       return sym;\r
+}\r
+\r
+\r
+struct yaffs_DeviceStruct *yramsim_CreateSim(const YCHAR *name,int nBlocks)\r
+{\r
+       void *sym = (void *)yramsim_AllocSymData(nBlocks);\r
+       ynandif_Geometry *g;\r
+\r
+       g = YMALLOC(sizeof(ynandif_Geometry));\r
+       \r
+       if(!sym || !g){\r
+               if(sym)\r
+                       YFREE(sym);\r
+               if(g)\r
+                       YFREE(g);\r
+               return NULL;\r
+       }\r
+\r
+       memset(g,0,sizeof(ynandif_Geometry));\r
+       g->startBlock = 0;\r
+       g->endBlock = nBlocks - 1;\r
+       g->dataSize = DATA_SIZE;\r
+       g->spareSize= SPARE_SIZE;\r
+       g->pagesPerBlock = PAGES_PER_BLOCK;\r
+       g->hasECC = 1;\r
+       g->inbandTags = 0;\r
+       g->useYaffs2 = 1;\r
+       g->initialise = yramsim_Initialise;\r
+       g->deinitialise = yramsim_Deinitialise; \r
+       g->readChunk = yramsim_ReadChunk, \r
+       g->writeChunk = yramsim_WriteChunk,\r
+       g->eraseBlock = yramsim_EraseBlock,\r
+       g->checkBlockOk = yramsim_CheckBlockOk,\r
+       g->markBlockBad = yramsim_MarkBlockBad,\r
+       g->privateData = sym;\r
+\r
+       return yaffs_AddDeviceFromGeometry(name,g);\r
+}