📜 ⬆️ ⬇️

Hindu code in Microchip

It was necessary to quickly connect the SD card to the microcontroller, and the task seemed simple — a good microchip offers libraries for everything (ah, linking the libraries is not destiny) , but after a first glance at their code , the hair on my head began to move.

Those who communicated with the support of the microchip probably noticed that it often ends up in the Indian department of the office, and all would be nothing if there was no suspicion that the whole microchip at once moved to Bombay and typed Indian homeless students to write their libraries.


')
Do not think that I am now trying to bend the racially correct line - I didn’t have experience of communicating specifically with Hindus, but I know for sure that among ours there are also enough of them (if you don’t believe it, type “95” in Google ), but the concept of “Hindu code” appeared a long time ago and stuck quite firmly, although you will not find it in the politically correct Wikipedia (but Google knows exactly about it).
The Hindu code (not Indian or Indian) is a slang common name for extremely low-quality software code using simple but perverse “copy-paste” principles.
Why precisely Hindu?
According to rumors in India, for some time, there has been a practice of evaluating the programmer’s productivity based on the amount of written code. The more code, the more the programmer works, and, therefore, the higher his salary. Nimble Indians quickly figured out how to deceive unqualified customers.
Useful note from kaladhara
A resident of India is an Indian, and a Hindu is a follower of any trend of Hinduism. Thus, even the elderly Chukchi, professing Saivism (and probably writing in C ++) are Hindu.

So, if you want to learn how to program as they do in a microchip, follow these simple tips ...

0. More code - more profit!


The most important thing to remember when hiring a job in a microchip is: “They still pay for the lines of code!”. Therefore, by any means, increase the volume of source code. General advice, so without examples, include fantasy.

1. Classics of the genre


The classic of the Hindu cinema code genre is unshakable since its appearance, for a warm-up try to guess what is behind this piece of code contained in the file “MDD File System \ SD-SPI.c” on line 1042:

if(localCounter != 0x0000) { localPointer--; while(1) { SPIBUF = 0xFF; localPointer++; if((--localCounter) == 0x0000) { break; } while(!SPISTAT_RBF); *localPointer = (BYTE)SPIBUF; } while(!SPISTAT_RBF); *localPointer = (BYTE)SPIBUF; } 

do not rush to look into the ANSWER - it’s just
 //    (      )    while (localCounter--) { SPIBUF = 0xFF; while (!SPISTAT_RBF); *localPointer++ = SPIBUF; } //    ,        //      -    while (localCounter) { localCounter--; SPIBUF = 0xFF; while (!SPISTAT_RBF); *localPointer++ = SPIBUF; } 


2. Copy Paste


In the absence of fantasy, copy-peist is also suitable, although it is rumored that many employers check the code for copy-paste, the microchip is probably not one of them. Remember, never use macros to cut a bubble with a Hindu code, they are evil and ugly reduce the code. In an example, a piece repeated twenty times in the file “MDD File System \ FSIO.c”:

ctrl + v
 if (utfModeFileName) { utf16path++; i = *utf16path; } else { temppath++; i = *temppath; } 

In general, I do not tolerate copy-paste programming. If there was a desire to copy something, I immediately wonder where and what to rewrite. And if there is a need for the same piece of code that cannot be wrapped in a function, then instead of stupid copying, you can make a macro out of it, which will be more readable and easier to correct in the future:

simple and understandable replacement of the piece above
 #define getnextpathchar() ( utfModeFileName ? *++utf16path : *++temppath ) // -   ... i = getnextpathchar(); //    

The ratio of 10: 1 in favor of the first option, and taking into account the twenty-fold repetition in absolute terms, this is several hundred rupees!

3. Line code


Using cycles is evil. A linear program works much faster, without wasting time on conditional operators and transitions, and contains more lines of code.

feel free to do so
 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part3[1]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part3[0]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[5]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[4]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[3]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[2]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[1]; fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[0]; tempShift.byte.LB = lfnObject.LFN_Part1[8]; tempShift.byte.HB = lfnObject.LFN_Part1[9]; fileFoundString[fileFoundLfnIndex--] = tempShift.Val; tempShift.byte.LB = lfnObject.LFN_Part1[6]; tempShift.byte.HB = lfnObject.LFN_Part1[7]; fileFoundString[fileFoundLfnIndex--] = tempShift.Val; tempShift.byte.LB = lfnObject.LFN_Part1[4]; tempShift.byte.HB = lfnObject.LFN_Part1[5]; fileFoundString[fileFoundLfnIndex--] = tempShift.Val; tempShift.byte.LB = lfnObject.LFN_Part1[2]; tempShift.byte.HB = lfnObject.LFN_Part1[3]; fileFoundString[fileFoundLfnIndex--] = tempShift.Val; tempShift.byte.LB = lfnObject.LFN_Part1[0]; tempShift.byte.HB = lfnObject.LFN_Part1[1]; fileFoundString[fileFoundLfnIndex--] = tempShift.Val; 

The initialization of structures should be byte-by-byte; no simple type initializers should be written:

 const somestruct mystruct = {"Field1", 2, 4, 8 .... }; 

Feel free to do so, memset for losers, and this is real money
 gDataBuffer[0] = 0xEB; //Jump instruction gDataBuffer[1] = 0x3C; gDataBuffer[2] = 0x90; gDataBuffer[3] = 'M'; //OEM Name "MCHP FAT" gDataBuffer[4] = 'C'; gDataBuffer[5] = 'H'; gDataBuffer[6] = 'P'; gDataBuffer[7] = ' '; gDataBuffer[8] = 'F'; gDataBuffer[9] = 'A'; gDataBuffer[10] = 'T'; gDataBuffer[11] = 0x00; //Sector size gDataBuffer[12] = 0x02; gDataBuffer[13] = disk->SecPerClus; //Sectors per cluster gDataBuffer[14] = 0x20; //Reserved sector count gDataBuffer[15] = 0x00; disk->fat = 0x20 + disk->firsts; gDataBuffer[16] = 0x02; //number of FATs gDataBuffer[17] = 0x00; //Max number of root directory entries - 512 files allowed gDataBuffer[18] = 0x00; gDataBuffer[19] = 0x00; //total sectors gDataBuffer[20] = 0x00; gDataBuffer[21] = 0xF8; //Media Descriptor gDataBuffer[22] = 0x00; //Sectors per FAT gDataBuffer[23] = 0x00; gDataBuffer[24] = 0x3F; //Sectors per track gDataBuffer[25] = 0x00; gDataBuffer[26] = 0xFF; //Number of heads gDataBuffer[27] = 0x00; // Hidden sectors = sectors between the MBR and the boot sector gDataBuffer[28] = (BYTE)(disk->firsts & 0xFF); gDataBuffer[29] = (BYTE)((disk->firsts / 0x100) & 0xFF); gDataBuffer[30] = (BYTE)((disk->firsts / 0x10000) & 0xFF); gDataBuffer[31] = (BYTE)((disk->firsts / 0x1000000) & 0xFF); // Total Sectors = same as sectors in the partition from MBR gDataBuffer[32] = (BYTE)(secCount & 0xFF); gDataBuffer[33] = (BYTE)((secCount / 0x100) & 0xFF); gDataBuffer[34] = (BYTE)((secCount / 0x10000) & 0xFF); gDataBuffer[35] = (BYTE)((secCount / 0x1000000) & 0xFF); gDataBuffer[36] = fatsize & 0xFF; //Sectors per FAT gDataBuffer[37] = (fatsize >> 8) & 0xFF; gDataBuffer[38] = (fatsize >> 16) & 0xFF; gDataBuffer[39] = (fatsize >> 24) & 0xFF; gDataBuffer[40] = 0x00; //Active FAT gDataBuffer[41] = 0x00; gDataBuffer[42] = 0x00; //File System version gDataBuffer[43] = 0x00; gDataBuffer[44] = 0x02; //First cluster of the root directory gDataBuffer[45] = 0x00; gDataBuffer[46] = 0x00; gDataBuffer[47] = 0x00; gDataBuffer[48] = 0x01; //FSInfo gDataBuffer[49] = 0x00; gDataBuffer[50] = 0x00; //Backup Boot Sector gDataBuffer[51] = 0x00; gDataBuffer[52] = 0x00; //Reserved for future expansion gDataBuffer[53] = 0x00; gDataBuffer[54] = 0x00; gDataBuffer[55] = 0x00; gDataBuffer[56] = 0x00; gDataBuffer[57] = 0x00; gDataBuffer[58] = 0x00; gDataBuffer[59] = 0x00; gDataBuffer[60] = 0x00; gDataBuffer[61] = 0x00; gDataBuffer[62] = 0x00; gDataBuffer[63] = 0x00; gDataBuffer[64] = 0x00; // Physical drive number gDataBuffer[65] = 0x00; // Reserved (current head) gDataBuffer[66] = 0x29; // Signature code gDataBuffer[67] = (BYTE)(serialNumber & 0xFF); gDataBuffer[68] = (BYTE)((serialNumber / 0x100) & 0xFF); gDataBuffer[69] = (BYTE)((serialNumber / 0x10000) & 0xFF); gDataBuffer[70] = (BYTE)((serialNumber / 0x1000000) & 0xFF); gDataBuffer[82] = 'F'; gDataBuffer[83] = 'A'; gDataBuffer[84] = 'T'; gDataBuffer[85] = '3'; gDataBuffer[86] = '2'; gDataBuffer[87] = ' '; gDataBuffer[88] = ' '; gDataBuffer[89] = ' '; 


4. Inventing a bicycle or money from spaces


Another idea brought me to the idea of ​​the FileObjectCopy function in the file “MDD File System \ FSIO.c” on line 6065, I suspect that if they had more different structures, then there would be other SomeObjectCopy

the function itself
 void FileObjectCopy(FILEOBJ foDest, FILEOBJ foSource) { int size; BYTE* dest; BYTE* source; int Index; dest = (BYTE*)foDest; source = (BYTE*)foSource; size = sizeof(FSFILE); for (Index = 0; Index < size; Index++) { dest[Index] = source[Index]; } } 

Description fascinates simplicity:
The FileObjectCopy function is a FSFILE object.
If “exacy” == “exact” as follows from the code, then this is a profitable replacement of direct assignment of structures — a standard operation in ANSI C, a made by the compiler, it should be both faster and more compact since the hardware FSR / INDF registers are used. Memcpy (d, s, sizeof (s)) is suitable for different objects and it also works quickly, at least its assembly implementation.

not profitable version of FileObjectCopy, disassembled version of HITech C18
 ; *FileObject1 = *FileObject2; //     ;    MOVLW FileObject1 >> 8 MOVWF FSR1H MOVLW FileObject1 MOVWF FSR1L MOVLW FileObject2 >> 8 MOVWF FSR0H MOVLW FileObject2 MOVWF FSR0L ;  MOVLW sizeof(*FileObject) loop: MOVFF POSTINC0, POSTINC1 ;       DECFSZ WREG, F BRA loop 

Well, there are still trifles to inflate the code, with which you can add a couple - three lines, like:

 int FSerror (void) { return FSerrno; } 

Even if it is solely to make the variable read-only, then such a macro is enough for the compiler to swear where necessary:

 #define FSerror() ( FSerrno ) 


5. Comments with fanaticism


Comment on everything but the most non-obvious pieces (see Example 1.) If you have not yet achieved full enlightenment and there are two or three functions left in your Hindu program, create a “function description template”, include buzzwords there, in the section "Description" list again everything that was written above, but deployed. Especially the effect of multiplying lines of code is manifested with functions like "FSerror ()" from the example above.

even an empty hat looks meaningful
 /************************************************************************** Function: void func (void) Summary: Does a hard work Conditions: This function should not be called by the user Input: None Return Values: None Side Effects: None Description: This function will do <a hard work>, with <none> input parameter.... Remarks: Optimize code later **************************************************************************/ 


6. Use architecture features


All that has been written above is general advice for beginners in the path of enlightenment, applicable to any program, in almost any language. But the real fans of Shiva use every opportunity to create chaos. Given the curvature of the Harvard PIC controller architecture, the real gurus of the Hindu code will discover an unimaginable number of possibilities for using specific directives and other features of the curvature of C implementation in compilers.

Write the code in such a way that it can not even compile under different versions of the compilers, and use all the specific #pragma. In this case, each function will be present in versions for at least two compilers and three or four PIC architectures, for a total of up to 8 times the code magnification.

Once again, double the amount of code will be helped by the fact that the RAM and ROM pointers in the PIC compilers are different, that is, “char *” cannot be converted explicitly or implicitly to “const char *” in high tech or “const rom char *” in microchip . That, in general, there are no problems at all in high-tech, since void, far and const pointers can address all memory and apply to both ROM and RAM. But in the microchip implementation of C, this can lead to the creation of two functions: one working with ROM, and the other with RAM — pure profit. You should never be satisfied with one function working with RAM (and, if necessary, loading constants from ROM).

And finally, always use inline assembler even in cases where your code is much longer and slower than what the compiler does from the normal C program. The assembler looks cool and most will not suspect what kind of stupidity was attached when it was created, and they will also consider that the program is written by one of the most optimal possible methods.

Instead of conclusion


Trying to get a microchip miracle to work (their website still got up), I spent a little more time than the one for which I wrote my implementation of working with SD and ported the file system taken here , which I warn you about - more accurate: “glitch inside”.

Source: https://habr.com/ru/post/150982/


All Articles