|
ECC的全稱是Error Checking and Correction,是一種用於Nand的差錯檢測和修正算法。如果操作時序和電路穩定性不存在問題的話,NAND Flash出錯的時候一般不會造成整個Block或是Page不能讀取或是全部出錯,而是整個Page(例如512Bytes)中只有一個或幾個bit出錯。ECC能糾正1個比特錯誤和檢測2個比特錯誤,而且計算速度很快,但對1比特以上的錯誤無法糾正,對2比特以上的錯誤不保證能檢測。
校驗碼生成算法的C語言實現 已經知道,異或運算的作用是判斷比特位為1的個數,跟比特位為0的個數沒有關系。如果有偶數個1則異或的結果為0,如果有奇數個1則異或的結果為1。 圖表 1 出錯Bit列地址定位的判決樹 注意:圖中的CP指的是求異或之后的結果中的CP 為什么只用CP4,CP2,CP0呢?其實這里面包含冗余信息,因為CP5=1則必有CP4=0,CP5=0則必有CP4=1,也就是CP5跟CP4一定相反,同理,CP3跟CP2一定相反,CP1跟CP0一定相反。所以只需要用一半就行了。 這樣,我們從異或結果中抽取出CP5,CP3,CP1位,便可定位出錯Bit位的列地址。比如上面的例子中CP5/CP3/CP1 = 001,表示Bit 1出錯。 同理,行校驗RP1發生變化,抽取RP1,可知Byte 1發生變化。這樣定位出Byte 1的Bit 0出錯。 當數據位256字節時,行校驗使用RP0 ~ RP15,抽取異或結果的RP15,RP13,RP11,RP9,RP7,RP5,RP3,RP1位便可定位出哪個Byte出錯,再用CP5,CP3,CP1定位哪個Bit出錯。
|
原文地址 http://linux.chinaunix.net/bbs/viewthread.php?tid=1116253&extra=page%3D1
終於基本看懂了。。。。
下面解釋一下,也許可以給和我曾經一樣迷茫的人一點幫助:
對於這個,別人總結出來的規則:
RP0只計算行索引的Bit0為0的行,RP1只計算行索引的Bit0為1的行;
RP2只計算行索引的Bit1為0的行,RP3只計算行索引的Bit1為1的行;
RP4只計算行索引的Bit2為0的行,RP5只計算行索引的Bit2為1的行;
RP6只計算行索引的Bit3為0的行,RP7只計算行索引的Bit3為1的行;
RP8只計算行索引的Bit4為0的行,RP9只計算行索引的Bit4為1的行;
RP10只計算行索引的Bit5為0的行,RP11只計算行索引的Bit5為1的行;
RP12只計算行索引的Bit6為0的行,RP13只計算行索引的Bit6為1的行;
RP14只計算行索引的Bit7為0的行,RP15只計算行索引的Bit7為1的行;
在接下來的描述中,稱為行與位的對應關系
另注:
1.上述規則中的RP意思是Row Parity,更多的叫法叫做LP(Line Parity)。為了解釋更容易看懂,依舊采用RP的說法。
2.對於第幾行,采用Line的說法,比如第1行,其實就是行號為0的Line0.
3.對於行的奇偶性,此處采用Line Parity的說法。
當Line5的Line Parity為1的時候,
首先最簡單的理解,也是最直接的理解,那就是,要把所有RP0~RP14中,對應包含着此行的那些最后要計算的值找出來,
我們可以先手動地根據下圖:
一點點,掰手指頭,慢慢地寫出來,那就是:
RP1,RP2,RP5,RP6,RP8,RP10,RP12,RP14
換句話說,如果Line5的Line Parity為1的時候,
我們應該要計算RP1,RP2,RP5,RP6,RP8,RP10,RP12,RP14。
關於這點,我想大家沒有什么好疑問的吧,因為這就是按照其規則的最簡單,最通俗的理解。
所以,不論你用什么復雜的算法,反正是要記錄並且計算這些RP的值,以便和后面的值進行計算。
但是,程序在此處,並沒有將這些RP找出來,而只是直接對行號進行XOR異或:
reg3 ^= (uint8_t) i;
表面上看,這和我們要找出來,並計算的那些RP,並沒啥關系,這也是我開始很困惑的問題。
按理來說,應該是找出那些行號,然后計算對應的RP的值,並保存,這樣才對。
而此處之所以可以這么處理,主要是有以下原因:
1. 行與位的有如下對應關系:
RP0只計算行索引的Bit0為0的行,RP1只計算行索引的Bit0為1的行;
RP2只計算行索引的Bit1為0的行,RP3只計算行索引的Bit1為1的行;
RP4只計算行索引的Bit2為0的行,RP5只計算行索引的Bit2為1的行;
RP6只計算行索引的Bit3為0的行,RP7只計算行索引的Bit3為1的行;
RP8只計算行索引的Bit4為0的行,RP9只計算行索引的Bit4為1的行;
RP10只計算行索引的Bit5為0的行,RP11只計算行索引的Bit5為1的行;
RP12只計算行索引的Bit6為0的行,RP13只計算行索引的Bit6為1的行;
RP14只計算行索引的Bit7為0的行,RP15只計算行索引的Bit7為1的行;
2. 某一行號的二進制分解的對應bit,對應了所要計算的RP:
比如是第6行,也就是Line5,5的二進制是:
| Bit7 |
Bit6 |
Bit5 |
Bit4 |
Bit3 |
Bit2 |
Bit1 |
Bit0 |
| 0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
5的二進制值
而根據上面別人分析出來的,行與位的對應關系,我們可以找出,此二進制的每一位所對應了哪些RP:
bit為1的位,分別是0,2,對應代表的是RP1,RP5
bit為0的位,分別是1,3,4,5,6,7,對應代表的是RP2,RP6,RP8,RP10,RP12,RP14
用表格表示為:
| Bit7 |
Bit6 |
Bit5 |
Bit4 |
Bit3 |
Bit2 |
Bit1 |
Bit0 |
| 0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
| RP14 |
RP12 |
RP10 |
RP8 |
RP6 |
RP5 |
RP2 |
RP1 |
5的二進制值和二進制對應的行
上表中,比如bit2是1,而別人說了“RP5只計算行索引的Bit2為1的行”,
所以,此處如果bit2為1,對應着RP5將要被計算,
那么我們可以肯定地得出來的是,
如果此行,Line5,的Line Parity是1的話,RP5是要被計算的。
而仔細觀察就會發現,RP5,就包含在我們上面自己手動找出來的那些LP中:
RP1,RP2,RP5,RP6,RP8,RP10,RP12,RP14
而,剩下的bit位,也依次對應着這些LP。比如bit0為1,對應RP1.
這就是我們上面說的“某一行號的二進制分解的對應bit,對應了所要計算的RP”
也是理解如此處理的關鍵點之一。
同樣地,除了bit為1的bit0,bit2,對應的RP1,RP5之外,
剩下的幾個bit對應的RP2,RP6,RP8,RP10,RP12,RP14,由於對應位是0,所以,即使拿過來抑或,也還是0,無法記住這些bit的值,所以,采用將其取反,這樣,對應這些為0的bit,就變成1了,就可以記住這些對應的bit了:
reg2 ^= ~((uint8_t) i);
這樣,當從0到255檢測的過程中,如果發現某行的Line Parity是1,
那么就將其行號數值進行抑或,以存儲奇數的LP,將行號取反,以保存偶數的LP,
也就是:
Reg3對應的就是RP1,RP3,RP5,。。。,RP15
Reg2對應的就是RP0,RP2,RP4,。。。,RP14
然后再調用函數nand_trans_result(reg2, reg3, ecc_code);去將reg3和reg2中存儲的信息,
重新組織到ecc[1]和ecc[2]中去。
最后的感慨是:
此處僅僅是通過對行號的數值抑或,以保存所要求的各個RP的值,之所以讓人很難理解:
一是由於我們之前不知道上面的那個規則:“行與位的對應關系”
二是我們不知道,行號按位分解后,對應的bit位對應着所要計算的那些RP,“某一行號的二進制分解的對應bit,對應了所要計算的RP”
最后感謝各位作者和分享其分析過程的朋友。
代碼:
Testecc.c
/* * ===================================================================================== * * Filename: TestEcc.c * * Description: * * Version: 1.0 * Created: 2009年06月04日 20時15分54秒 * Revision: none * Compiler: gcc * * Author: Li Hongwang (mn), hoakee@gmail.com * Company: University of Science and Technology of China * * ===================================================================================== */ #include <stdio.h> typedef unsigned char u_char; typedef unsigned char uint8_t; typedef unsigned int uint32_t; /* * Pre-calculated 256-way 1 byte column parity */ static const u_char nand_ecc_precalc_table[] = { 0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00, 0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65, 0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66, 0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03, 0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69, 0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C, 0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F, 0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A, 0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A, 0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F, 0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C, 0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69, 0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03, 0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66, 0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65, 0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00 }; /** * * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block * * @mtd: MTD block structure * * @dat: raw data * * @ecc_code: buffer for ECC * */ int nand_calculate_ecc(const u_char *dat, u_char *ecc_code) { uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; int i; /* Initialize variables */ reg1 = reg2 = reg3 = 0; /* Build up column parity */ for(i = 0; i < 256; i++) { /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[*dat++]; reg1 ^= (idx & 0x3f); /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (uint8_t) i; reg2 ^= ~((uint8_t) i); } } /* Create non-inverted ECC code from line parity */ tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ /* Calculate final ECC code */ #ifdef CONFIG_MTD_NAND_ECC_SMC //ecc_code[0] = ~tmp2; //ecc_code[1] = ~tmp1; #else //ecc_code[0] = ~tmp1; //ecc_code[1] = ~tmp2; #endif ecc_code[0] = tmp2; ecc_code[1] = tmp1; //ecc_code[2] = ((~reg1) << 2) | 0x03; ecc_code[2] = ((reg1) << 2) | 0x03; return 0; } static inline int countbits(uint32_t byte) { int res = 0; for (;byte; byte >>= 1) res += byte & 0x01; return res; } int nand_correct_data( u_char *read_ecc, u_char *calc_ecc) { uint8_t s0, s1, s2; s0 = calc_ecc[0] ^ read_ecc[0]; s1 = calc_ecc[1] ^ read_ecc[1]; s2 = calc_ecc[2] ^ read_ecc[2]; if ((s0 | s1 | s2) == 0) return 0; /* Check for a single bit error */ if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { uint32_t byteoffs, bitnum; byteoffs = (s1 << 0) & 0x80; byteoffs |= (s1 << 1) & 0x40; byteoffs |= (s1 << 2) & 0x20; byteoffs |= (s1 << 3) & 0x10; byteoffs |= (s0 >> 4) & 0x08; byteoffs |= (s0 >> 3) & 0x04; byteoffs |= (s0 >> 2) & 0x02; byteoffs |= (s0 >> 1) & 0x01; bitnum = (s2 >> 5) & 0x04; bitnum |= (s2 >> 4) & 0x02; bitnum |= (s2 >> 3) & 0x01; printf("Error Bit at: Byte %d, Bit %d.\n", byteoffs, bitnum); return 1; } if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) return 1; return -1; } // static const u_char raw_data[] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF }; // changed data. 0x34==>0x74 static const u_char new_data[] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, 0x30,0x31,0x32,0x33,0x74,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF }; static uint8_t ecc_code_raw[3]; static uint8_t ecc_code_new[3]; int main() { int i=0; nand_calculate_ecc( raw_data, ecc_code_raw ); nand_calculate_ecc( new_data, ecc_code_new ); printf("\nRaw ECC Code: "); for( i=0; i< 3; i++) { printf("0x%02X ", ecc_code_raw[i] ); } printf("\nNew ECC Code: "); for( i=0; i< 3; i++) { printf("0x%02X ", ecc_code_new[i] ); } printf("\n"); nand_correct_data( ecc_code_raw, ecc_code_new ); printf("\n"); }

![clip_image002[1] clip_image002[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjY1Mi02ZjU3MmMwZjg5NmE0YmNiYTMxYWZlOGZkMjhjZmYyZi5qcGc=.png)
![clip_image004[2] clip_image004[2]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjcwMS1kYzEzYmE3MjE0NTI0ZGUzYTIwOGIxYjY5MjEzNTExMC5qcGc=.png)
![clip_image006[1] clip_image006[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjcxMC1kYjM2YmMxM2M5ZjM0M2E4OGYyZWFhODQ3MDQ4OGViNy5qcGc=.png)
![clip_image009[1] clip_image009[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjcxOC00OTQ5NDMyMWIwMTg0YjM5YjQwZDY5NzNmNGU5ODk2OS5qcGc=.png)
![clip_image011[1] clip_image011[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjcyNi1iZGQ5MjY2NWE1MGU0MmMyODUyOTcwMzlkNGZiODM1OC5qcGc=.png)
![clip_image013[1] clip_image013[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjcyOS02MGJhMTA3MTliNTY0YmM3YTkxZmM3MDk0MWYyMzU1Mi5qcGc=.png)
![clip_image015[1] clip_image015[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjczMi02NWViNzNjMmUzNGY0YWMzYTJkMDAyNDhkZDQwNzgyNy5qcGc=.png)
![clip_image017[1] clip_image017[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjczNS1mZjQxYzE4YmNkNjM0Yzk0ODg0NDRmNTg4NjNkOTVjMS5qcGc=.png)
![clip_image019[1] clip_image019[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3MjczOS0yNWViM2NmM2M0ZDA0ZmE0ODk0OTExZTlhODEwOTk4ZC5qcGc=.png)
![clip_image021[1] clip_image021[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3Mjc0Mi1kODcyZTM4MDQ0ZWI0YjQxYTc0NTQzYWQ2ZWExYmRlNi5qcGc=.png)
![clip_image023[1] clip_image023[1]](/image/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDgwNDg4LzIwMTMxMS8yMjE3Mjc0Ny1lMThiMGYzNjgwZTQ0YzNkODhjN2JmNmM0OTEzMThmZi5naWY=.png)