/****************************************************************** * Created: Josep Valls 20080211 * Simple shell for CMPS105/Winter2008 * Code for limited devices and practice direct memory access and volatile registers * Features: This code is a modified version to show how the blinking effect is properly handled ******************************************************************/ //general typedef unsigned short u16; typedef unsigned char u8; //the vertical line being draw, volatile as changed outside of code #define VBLANK_CNT *(volatile unsigned short*)0x4000006 //this controls vid mode, bkgs, objs etc #define REG_DISPCNT *(unsigned short*)0x4000000 //controls which buffer is active in mode 4/5 #define BACKBUFFER 0x10 //globals // create a pointer to the video buffer unsigned short* videoBuffer = (unsigned short*)0x6000000; unsigned short* videoBuffer1 = (unsigned short*)0x6000000; unsigned short* videoBuffer2 = (unsigned short*)0x600A000; // create a pointer to the palette unsigned short* videoPalette = (unsigned short*)0x5000000; //16 bit RGB function #define RGB16(r,g,b) ((r)+(g<<5)+(b<<10)) //will wait for screen redraw without interrupts void WaitVBlank(void){ while (VBLANK_CNT<160) {}; //do nothing untill vblank has completed } //this swaps the locations of the current display and current writing location void SwapBuffer(void) { if (REG_DISPCNT&BACKBUFFER) //backbuffer is being displayed so swap { REG_DISPCNT &= ~BACKBUFFER; //make display show the frontbuffer (remove backbuffer using it's bitwise compliement) videoBuffer=(unsigned short*)videoBuffer2; //make backbuffer the one we draw to } else //frontbuffer is being displayed so swap { REG_DISPCNT|=BACKBUFFER; //make display show the backbuffer (add backbuffer) videoBuffer=(unsigned short*)videoBuffer1; //make frontbuffer the one we draw to } } //prototypes int changePalette(int); void drawSomething(void); void moveBuffer(void); // entry point to program int main(void) { // switch to video mode 4 (240x160 8-bit) *(unsigned long*)0x4000000 = (0x4 | 0x400); //initialization u16 x,y; u8 pal; //set a palette changePalette(0); //Adds some spice for the effects for (x=0;x<120*160;x++) videoBuffer[rand() % (120*160)]=rand()%0xFF; for (x=0;x<6;x++) { moveBuffer(); SwapBuffer(); } int currentPalette=31; // continuous loop while(1) { WaitVBlank(); currentPalette=changePalette(currentPalette); } return 0; // end program } //Sets a palette with a gradient int changePalette(int p){ u16 x; p++; for(x=0;x<256;x++){ videoPalette[x]=RGB16(31-(int)x*31/256,abs(p-31),(int)x*31/256); } if (p==62) p=0; return p; } //Just plots a dot (two actually in mode 4) in the first line void drawSomething(void){ videoBuffer[rand() % 120]=rand()%0xFF; } //This function is supposed to be processor intensive //Will average some points and move those down, from one buffer to the other void moveBuffer(void){ unsigned short* bFrom; unsigned short* bTo; u16 x,y,y2; u8 pixel1,pixel2,pixel0,pixel3; if (REG_DISPCNT&BACKBUFFER){ bFrom=(unsigned short*)videoBuffer2; bTo=(unsigned short*)videoBuffer1; }else{ bFrom=(unsigned short*)videoBuffer1; bTo=(unsigned short*)videoBuffer2; } for (y=0;y<160;y++){ for (x=0;x<120;x++){ pixel1=bFrom[y*120+x]&0x00FF; pixel2=(bFrom[y*120+x]&0xFF00)>>8; pixel0=bFrom[(y*120+x)-1]&0x00FF; pixel3=(bFrom[(y*120+x)+1]&0xFF00)>>8; pixel1=(pixel1*3+pixel0+pixel2)/5; pixel2=(pixel2*3+pixel1+pixel3)/5; if(y==159) y2=0; else y2=y; bTo[y2*120+x+120]=pixel1|(pixel2<<8); } } //for (x=0;x<120*159;x++) //bTo[x+120]=bFrom[x]; }