view src/cs/drivers/drv_app/r2d/lcds/R2D_vertical_lcd_i.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents 4e78acac3d88
children
line wrap: on
line source

#if (R2D_PIXEL_DEPTH == 32)
#define R2D_PIXEL_DOWN_OUT(a) (0)
#define R2D_PIXEL_UP_OUT(a) (0)
#else
#define R2D_PIXEL_DOWN_OUT(a) (a>>R2D_PIXEL_DEPTH)
#define R2D_PIXEL_UP_OUT(a) (a<<R2D_PIXEL_DEPTH)
#endif

#if (R2D_ASM == R2D_ON)

// All below global are modified in the context of a blit_rect and
// the use of the self modifying blit_rect is protected by
// a semaphore

extern T_R2D_DRAWING_MODE r2d_g_old_mode;
extern R2D_BOOLEAN r2d_g_old_use_foreground;
extern INT32 r2d_g_old_srcdst;
extern UINT32 r2d_g_old_foreground_pixelvalue;
extern UINT32 r2d_g_old_background_pixelvalue;

extern void r2d_blit_la(UINT32 *a);
extern void r2d_blit_lb(UINT32 *a);

#endif

extern BOOLEAN IND_r2d_color_framebuffer_foreground_pixel(UINT32 lcd_value,T_R2D_GC_PTR src_gc);


#define r2d_get_texture_color() ((T_R2D_ANCHORED_TEXTURE*)(gc->background_texture))->pattern[((x-gc->s_org_x)&texture_mask)*texture_size+((ty-gc->s_org_y)&texture_mask)]






void r2d_write_lcd_line(T_R2D_GC* gc,INT16 x,INT16 y,INT16 nb,R2D_BOOLEAN background)
{
  UINT32 *p;
  UINT16 tmp,ty;
//  UINT32 temp;
  UINT32 pixel_cache,pixel_value;
  INT16 current_y,count;
  UINT32 new_value,current_value;
  T_R2D_DRAWING_OP dop;
  INT16 texture_mask,texture_size;

  ty=y; // True y

  if (gc->background_texture!=NULL)
  {
	  texture_mask=~((-1)<<gc->background_texture->size);
	  texture_size=1<<gc->background_texture->size;
  }

  dop=gc->drawing_op;
  
  if (nb==0) 
   goto r2d_fail_line;

  p=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words;

  switch(((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->kind)
  {
    case 0:// LCD format with hard coded dimensions

		{

       // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
       p+=((x*R2D_MWHEIGHT+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
	   p+=((x*R2D_MWWIDTH+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif

         if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
         || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
         {
           #if (R2D_DEBUG == R2D_ON)
              //printf("Error : frame_buffer overflow\n");
			  IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

           #endif
           goto r2d_fail_line;
         }



       // Get the pixel position into the memory word
	   new_value=0;
       y=y & R2D_WORD_POSITION_MASK;
	   y=y << R2D_PIXEL_POS_TO_BIT_POS;
       pixel_cache=*p;
       current_y=0;
       current_value=pixel_cache;
       if (y!=0)
       {
          do
          {
            new_value =R2D_PIXEL_DOWN_OUT(new_value);
            new_value|=((current_value & R2D_PIXEL_MASK)
              << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
            current_value=R2D_PIXEL_DOWN_OUT(current_value);
            current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
          } while (current_y != y);
       }
       count=0;
	   #if (R2D_DITHERING == R2D_OFF)
             if (background)
			 	pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
			 else
				 pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
       #endif
       do
       {
		 #if (R2D_DITHERING == R2D_ON)
           if (background)
		   {
			 if (gc->background_texture!=NULL)
			   pixel_value=r2d_get_texture_color();
             else
			   pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_background_dithered_cache,x,ty);
            
		   }
		   else
             pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_foreground_dithered_cache,x,ty);
         #endif

         #if (R2D_DITHERING == R2D_OFF)
		   if ((background) && (gc->background_texture!=NULL))
			pixel_value=r2d_get_texture_color();
         #endif
		 
		 ty++;

         new_value =R2D_PIXEL_DOWN_OUT(new_value);
		 
         new_value|=((dop(current_value & R2D_PIXEL_MASK,pixel_value) & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
         if (current_y==(1<<R2D_MEMORY_WORD))
         {
            current_y=0;
            *p++=new_value;
            current_value=*p;
         }
         count++;
      } while (count<nb);

       while(current_y != (1<<R2D_MEMORY_WORD))
       {
         new_value =R2D_PIXEL_DOWN_OUT(new_value) ;
         new_value|=((current_value & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
       }
       *p++=new_value;

  }
    break;
    case R2D_LCD_KIND: // LCD format with any size
    {
       INT16 height,width;
       height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
       width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
      
       // Get position of the memory word containing the pixel
	#if (R2D_REFRESH == R2D_VERTICAL)
       p+=((x*R2D_ALIGNED_MWLENGTH(height)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
	   p+=((x*R2D_ALIGNED_MWLENGTH(width)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif

         if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
         || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
         {
           #if (R2D_DEBUG == R2D_ON)
              IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
           #endif
           goto r2d_fail_line;
         }



       // Get the pixel position into the memory word
	   new_value=0;
       y=y & R2D_WORD_POSITION_MASK;
	   y=y << R2D_PIXEL_POS_TO_BIT_POS;
       pixel_cache=*p;
       current_y=0;
       current_value=pixel_cache;
       if (y!=0)
       {
          do
          {
            new_value =R2D_PIXEL_DOWN_OUT(new_value) ;
            new_value|=((current_value & R2D_PIXEL_MASK)
              << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
            current_value=R2D_PIXEL_DOWN_OUT(current_value);
            current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
          } while (current_y != y);
       }
       count=0;
	   #if (R2D_DITHERING == R2D_OFF)
             if (background)
				 pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
			 else
				 pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
       #endif
       do
       {
		 #if (R2D_DITHERING == R2D_ON)
           if (background)
			  if (gc->background_texture!=NULL)
                pixel_value=r2d_get_texture_color();
			  else
                pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_background_dithered_cache,x,ty);   
           else
             pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_foreground_dithered_cache,x,ty);      
         #endif

         #if (R2D_DITHERING == R2D_OFF)
            if ((background) && (gc->background_texture!=NULL))
			   pixel_value=r2d_get_texture_color();
            #endif

		 ty++;

         new_value =R2D_PIXEL_DOWN_OUT(new_value);
         new_value|=((dop(current_value & R2D_PIXEL_MASK,pixel_value) & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
         if (current_y==(1<<R2D_MEMORY_WORD))
         {
            current_y=0;
            *p++=new_value;
            current_value=*p;
         }
         count++;
      } while (count<nb);

       while(current_y != (1<<R2D_MEMORY_WORD))
       {
         new_value =R2D_PIXEL_DOWN_OUT(new_value);
         new_value|=((current_value & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
       }
       *p++=new_value;

   
    }
       break;

    case R2D_FULL_KIND: // LCD format with any size
    {
       INT16 height,width;
       height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
       width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
       

       // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
       p+=((x*height+y));
#else
	   p+=((x*width+y));
#endif

         if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
         || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
         {
           #if (R2D_DEBUG == R2D_ON)
              IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
           #endif
           goto r2d_fail_line;
         }



       // Get the pixel position into the memory word
       y=0;
	   new_value=0;
       pixel_cache=*p;
       current_y=0;
       current_value=pixel_cache;
       count=0;
       if (background)
       {
           pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
       }
       else
       {
           pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
       }

       do
       {
		 
            if ((background) && (gc->background_texture!=NULL))
			   pixel_value=r2d_get_texture_color();

		 ty++;
         new_value=dop(current_value,pixel_value);
         current_y=0;
         *p++=new_value;
         current_value=*p;
         count++;
      } while (count<nb);


    
    }
       break;
  }
  r2d_fail_line:tmp=0; // Just because one needs code after a label
}

void r2d_arc_write_lcd_line(T_R2D_GC* gc,INT16 x,INT16 y,
							INT16 org_x,INT16 org_y,INT16 nb,
							T_R2D_ARC_REGION *rgn,R2D_BOOLEAN background)
{
  UINT32 *p;
  UINT16 tmp,ty;
//  UINT32 temp;
  UINT32 pixel_cache,pixel_value;
  INT32 current_y,count;
  UINT32 new_value,current_value;
  T_R2D_DRAWING_OP dop;
  INT16 texture_mask,texture_size;
  INT32 sides,sidee;
  BOOLEAN start_filling=FALSE;

  sides=r2d_get_point_side((INT16)(x-org_x),(INT16)(y-org_y),rgn->sa,rgn->sb);
  sidee=r2d_get_point_side((INT16)(x-org_x),(INT16)(y-org_y),rgn->ea,rgn->eb);

  ty=y; // True y

  if (gc->background_texture!=NULL)
  {
	  texture_mask=~((-1)<<gc->background_texture->size);
	  texture_size=1<<gc->background_texture->size;
  }

  dop=gc->drawing_op;
  
  if (nb==0) 
   goto r2d_fail_line;

  p=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words;

  switch(((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->kind)
  {
    case 0:// LCD format with hard coded dimensions

		{

       // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
       p+=((x*R2D_MWHEIGHT+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
	   p+=((x*R2D_MWWIDTH+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif

         if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
         || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
         {
           #if (R2D_DEBUG == R2D_ON)
              //printf("Error : frame_buffer overflow\n");
			  IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

           #endif
           goto r2d_fail_line;
         }



       // Get the pixel position into the memory word
	   new_value=0;
       y=y & R2D_WORD_POSITION_MASK;
	   y=y << R2D_PIXEL_POS_TO_BIT_POS;
       pixel_cache=*p;
       current_y=0;
       current_value=pixel_cache;
       if (y!=0)
       {
          do
          {
            new_value =R2D_PIXEL_DOWN_OUT(new_value);
            new_value|=((current_value & R2D_PIXEL_MASK)
              << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
            current_value=R2D_PIXEL_DOWN_OUT(current_value);
            current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
          } while (current_y != y);
       }
       count=0;
	   #if (R2D_DITHERING == R2D_OFF)
             if (background)
			 	pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
			 else
				 pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
       #endif
       do
       {
		 #if (R2D_DITHERING == R2D_ON)
           if (background)
		   {
			 if (gc->background_texture!=NULL)
			   pixel_value=r2d_get_texture_color();
             else
			   pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_background_dithered_cache,x,ty);
            
		   }
		   else
             pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_foreground_dithered_cache,x,ty);
         #endif

         #if (R2D_DITHERING == R2D_OFF)
		   if ((background) && (gc->background_texture!=NULL))
			pixel_value=r2d_get_texture_color();
         #endif
		 
		 

         new_value =R2D_PIXEL_DOWN_OUT(new_value);
		 
		 if (
			 ((rgn->one_sector==0) && (sides>=0) && (sidee>=0))
			 || 
			 ((rgn->one_sector==1) && (!(!(sides>=0) && !(sidee>=0))))
			 || (rgn->one_sector==2)
			 )
		 {
			 if (rgn->one_sector==0)
			start_filling=TRUE;
            new_value|=((dop(current_value & R2D_PIXEL_MASK,pixel_value) & R2D_PIXEL_MASK)
              << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
		 }
		 else
		 {
		   if (start_filling)
			   goto r2d_fail_line;
           new_value|=(current_value & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH) ;
		 }

		 ty++;
		 sides+=-(rgn->sa>>1);
		 sidee+=-(rgn->ea>>1);

         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
         if (current_y==(1<<R2D_MEMORY_WORD))
         {
            current_y=0;
            *p++=new_value;
            current_value=*p;
         }
         count++;
      } while (count<nb);

       while(current_y != (1<<R2D_MEMORY_WORD))
       {
         new_value =R2D_PIXEL_DOWN_OUT(new_value) ;
         new_value|=((current_value & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
       }
       *p++=new_value;

  }
    break;
    case R2D_LCD_KIND: // LCD format with any size
    {
       INT16 height,width;
       height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
       width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
      
       // Get position of the memory word containing the pixel
	#if (R2D_REFRESH == R2D_VERTICAL)
       p+=((x*R2D_ALIGNED_MWLENGTH(height)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
	   p+=((x*R2D_ALIGNED_MWLENGTH(width)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif

         if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
         || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
         {
           #if (R2D_DEBUG == R2D_ON)
              IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
           #endif
           goto r2d_fail_line;
         }



       // Get the pixel position into the memory word
	   new_value=0;
       y=y & R2D_WORD_POSITION_MASK;
	   y=y << R2D_PIXEL_POS_TO_BIT_POS;
       pixel_cache=*p;
       current_y=0;
       current_value=pixel_cache;
       if (y!=0)
       {
          do
          {
            new_value =R2D_PIXEL_DOWN_OUT(new_value) ;
            new_value|=((current_value & R2D_PIXEL_MASK)
              << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
            current_value=R2D_PIXEL_DOWN_OUT(current_value);
            current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
          } while (current_y != y);
       }
       count=0;
	   #if (R2D_DITHERING == R2D_OFF)
             if (background)
				 pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
			 else
				 pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
       #endif
       do
       {
		 #if (R2D_DITHERING == R2D_ON)
           if (background)
			  if (gc->background_texture!=NULL)
                pixel_value=r2d_get_texture_color();
			  else
                pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_background_dithered_cache,x,ty);   
           else
             pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_foreground_dithered_cache,x,ty);      
         #endif

         #if (R2D_DITHERING == R2D_OFF)
            if ((background) && (gc->background_texture!=NULL))
			   pixel_value=r2d_get_texture_color();
            #endif

		 

         new_value =R2D_PIXEL_DOWN_OUT(new_value);

		 if (
			 ((rgn->one_sector==0) && (sides>=0) && (sidee>=0))
			 || 
			 ((rgn->one_sector==1) && (!(!(sides>=0) && !(sidee>=0))))
			 || (rgn->one_sector==2)
			 )
		 {
			 if (rgn->one_sector==0)
			 start_filling=TRUE;
           new_value|=((dop(current_value & R2D_PIXEL_MASK,pixel_value) & R2D_PIXEL_MASK)
             << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         }
		  else
		  {
			  if (start_filling)
			   goto r2d_fail_line;
          new_value|=((current_value & R2D_PIXEL_MASK)
             << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
		  }
		 ty++;
		 sides+=-(rgn->sa>>1);
		 sidee+=-(rgn->ea>>1);

		 current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
         if (current_y==(1<<R2D_MEMORY_WORD))
         {
            current_y=0;
            *p++=new_value;
            current_value=*p;
         }
         count++;
      } while (count<nb);

       while(current_y != (1<<R2D_MEMORY_WORD))
       {
         new_value =R2D_PIXEL_DOWN_OUT(new_value);
         new_value|=((current_value & R2D_PIXEL_MASK)
           << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ;
         current_value=R2D_PIXEL_DOWN_OUT(current_value);
         current_y+=(1<<R2D_PIXEL_POS_TO_BIT_POS);
       }
       *p++=new_value;

   
    }
       break;

    case R2D_FULL_KIND: // LCD format with any size
    {
       INT16 height,width;
       height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
       width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
       

       // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
       p+=((x*height+y));
#else
	   p+=((x*width+y));
#endif

         if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
         || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
         {
           #if (R2D_DEBUG == R2D_ON)
              IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
           #endif
           goto r2d_fail_line;
         }



       // Get the pixel position into the memory word
       y=0;
	   new_value=0;
       pixel_cache=*p;
       current_y=0;
       current_value=pixel_cache;
       count=0;
       if (background)
       {
           pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
       }
       else
       {
           pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
       }

       do
       {
		 
            if ((background) && (gc->background_texture!=NULL))
			   pixel_value=r2d_get_texture_color();

		 
         if (
			 ((rgn->one_sector==0) && (sides>=0) && (sidee>=0))
			 || 
			 ((rgn->one_sector==1) && (!(!(sides>=0) && !(sidee>=0))))
			 || (rgn->one_sector==2)
			 )
		 {
			 if (rgn->one_sector==0)
			 start_filling=TRUE;
            new_value=dop(current_value,pixel_value);
		 }
         else
		 {
			 if (start_filling)
			   goto r2d_fail_line;
            new_value=current_value;
		 }
		 ty++;
		 sides+=-(rgn->sa>>1);
		 sidee+=-(rgn->ea>>1);

         current_y=0;
         *p++=new_value;
         current_value=*p;
         count++;
      } while (count<nb);


    
    }
       break;
  }
  r2d_fail_line:tmp=0; // Just because one needs code after a label
}

// Returns the equivalent color pixel value
// for the color kind of framebuffer
// It must be converted to RGB components
// Don't confuse with r2d_get_pixel_value which is
// just reading the cached pixel vlue from
// the graphic context.
// That routine is extracting the pixel value at position (x,y)
// from framebuffer
UINT32 r2d_get_color_pixel_value(T_R2D_GC* gc,INT16 x,INT16 y)
{
  UINT32 *p;
//  UINT16 tmp;
  UINT32 pixel_cache;//,new_value;
  UINT32 result;

  p=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words;

  switch(((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->kind)
  {
    case 0: // LCD format with hard coded dimensions
		{
        // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
        p+=((x*R2D_MWHEIGHT+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
		p+=((x*R2D_MWWIDTH+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif

          if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
          || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
          {
            #if (R2D_DEBUG == R2D_ON)
               IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
            #endif
            goto r2d_fail_get_pixel;
          }


        // Get the pixel position into the memory word
        y=y & R2D_WORD_POSITION_MASK;
		y=y << R2D_PIXEL_POS_TO_BIT_POS;
        pixel_cache=*p;

        result=(pixel_cache >> y) & R2D_PIXEL_MASK;
        return((~IND_r2d_lcd_to_color(result)) & 0x00FFFFFF);
		}
    break;
    case R2D_LCD_KIND: // LCD format with any size
    {
      INT16 height,width;
      height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
      width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
     
#if (R2D_REFRESH == R2D_VERTICAL)
        // Get position of the memory word containing the pixel
        p+=((x*R2D_ALIGNED_MWLENGTH(height)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
		p+=((x*R2D_ALIGNED_MWLENGTH(width)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif


          if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
          || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
          {
            #if (R2D_DEBUG == R2D_ON)
               IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
            #endif
            goto r2d_fail_get_pixel;
          }


        // Get the pixel position into the memory word
        y=y & R2D_WORD_POSITION_MASK;
		y=y << R2D_PIXEL_POS_TO_BIT_POS;
        pixel_cache=*p;

        result=(pixel_cache >> y) & R2D_PIXEL_MASK;
        
        return(~IND_r2d_lcd_to_color(result) & 0x00FFFFFF);
    }
    break;
    case R2D_FULL_KIND:
    {
      INT16 height,width;
      height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
      width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
     
       //printf("%08X\n",p);
        // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
        p+=(x*height+y);
#else
		p+=(x*width+y);
#endif

       //printf(" --> %08X for x=%d and y=%d\n",p,x,y);


          if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
          || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
          {
            #if (R2D_DEBUG == R2D_ON)
               IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
            #endif
            goto r2d_fail_get_pixel;
          }


        // Get the pixel position into the memory word
        y=0;
        pixel_cache=*p;

        result=(~pixel_cache) & 0x00FFFFFF;
	}
    break;
  }
r2d_fail_get_pixel:return(0);
}

// Low level pixel drawing
// (Note that for filling a more efficient version is used
// taking into account the fact that the position
// in the framebuffer has not to be recomputed from the coordinates
// for each pixel)
void r2d_write_lcd_pixel(T_R2D_GC* gc,INT16 x,INT16 y,UINT32 pixel_value)
{
  UINT32 *p;
  UINT16 tmp;
  UINT32 pixel_cache,new_value;
  T_R2D_DRAWING_OP dop;

  dop=gc->drawing_op;

  p=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words;

  switch(((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->kind)
  {
    case 0: // LCD format with hard coded dimensions
		{
        // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
        p+=((x*R2D_MWHEIGHT+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
		p+=((x*R2D_MWWIDTH+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif

          if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
          || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
          {
            #if (R2D_DEBUG == R2D_ON)
               IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
            #endif
            goto r2d_fail_pixel;
          }


        // Get the pixel position into the memory word
        y=y & R2D_WORD_POSITION_MASK;
		y=y << R2D_PIXEL_POS_TO_BIT_POS;
        pixel_cache=*p;

        new_value=dop((pixel_cache >> y) & R2D_PIXEL_MASK,pixel_value) & R2D_PIXEL_MASK;
        pixel_cache &= ~(R2D_PIXEL_MASK << y) ;

        // Write new value
        pixel_cache |= (new_value << y);
        *p=pixel_cache;
		}
    break;
    case R2D_LCD_KIND: // LCD format with any size
    {
      INT16 height,width;
      height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
      width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
     
#if (R2D_REFRESH == R2D_VERTICAL)
        // Get position of the memory word containing the pixel
        p+=((x*R2D_ALIGNED_MWLENGTH(height)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#else
		p+=((x*R2D_ALIGNED_MWLENGTH(width)+(y>>R2D_PIXELS_PER_MEMORY_WORD)));
#endif


          if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
          || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
          {
            #if (R2D_DEBUG == R2D_ON)
               IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
            #endif
            goto r2d_fail_pixel;
          }


        // Get the pixel position into the memory word
        y=y & R2D_WORD_POSITION_MASK;
		y=y << R2D_PIXEL_POS_TO_BIT_POS;
        pixel_cache=*p;

        new_value=dop((pixel_cache >> y) & R2D_PIXEL_MASK,pixel_value) & R2D_PIXEL_MASK;
        pixel_cache &= ~(R2D_PIXEL_MASK << y) ;

        // Write new value
        pixel_cache |= (new_value << y);
        *p=pixel_cache;
     
    }
    break;
    case R2D_FULL_KIND:
    {
      INT16 height,width;
      height=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->height;
      width=((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->width;
     
       //printf("%08X\n",p);
        // Get position of the memory word containing the pixel
#if (R2D_REFRESH == R2D_VERTICAL)
        p+=(x*height+y);
#else
		p+=(x*width+y);
#endif

       //printf(" --> %08X for x=%d and y=%d\n",p,x,y);


          if ((y<0) || (x<0) || ((p<((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_memory_words) 
          || (p>((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->p_frame_buffer_end)))
          {
            #if (R2D_DEBUG == R2D_ON)
               IND_rvf_send_trace("R2D : Framebuffer overflow",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
            #endif
            goto r2d_fail_pixel;
          }


        // Get the pixel position into the memory word
        y=0;
        pixel_cache=*p;

        new_value=dop(pixel_cache,pixel_value);
        pixel_cache = new_value;
        *p=pixel_cache;
	}
    break;
  }
  r2d_fail_pixel:tmp=0; // Just because one needs code after a label
}




#if (R2D_ASM == R2D_OFF)



// For blitting, two scanning direction are required because of possible
// overlaps between src and dst

// Shift new pixel from srcstream to dststream using variable srccache
// as a pixel cache.dstcounter allows to keep track of number
// of pixels written
// (scanning direction is down)

#define r2d_shift_pixel_down(dststream,srccache,srccounter,srcstream) {dststream =R2D_PIXEL_DOWN_OUT(dststream); \
               dststream|=((srccache & R2D_PIXEL_MASK) \
               << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) ; \
               srccache=R2D_PIXEL_DOWN_OUT(srccache); \
               srccounter--; \
               if (srccounter==0) \
               { \
                 srccounter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 srccache=*++srcstream;  \
               } }


// Scanning direction is up
#define r2d_shift_pixel_up(dststream,srccache,srccounter,srcstream) {dststream =R2D_PIXEL_UP_OUT(dststream); \
               dststream |=(srccache >> ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) & R2D_PIXEL_MASK; \
               srccache=R2D_PIXEL_UP_OUT(srccache); \
               srccounter--; \
               if (srccounter==0) \
               { \
                 srccounter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 srccache=*--srcstream;  \
               } }

#endif

// Check overlap of src and dst rectangle and return the
// horizontal and vertical scanning direction required to do the
// blit rect
 
// A positive value means standard direction (increasing x and increasing y)
// When that routine is called, both rectangles are expressed in framebuffer
// coordinates and come from the same framebuffer.
// The routine is never called if dstGc and srcGc are not using the same framebuffer.
//
// INT32 used because of stack bug ?
void r2d_check_rectangle_overlap(INT16 src_x,INT16 src_y,INT16 dst_x,INT16 dst_y,
INT32 width,INT32 height,
INT32 *h_direction,INT32 *v_direction)
{
   INT16 h,v;
   INT16 rx,ry;
   rx=dst_x-src_x;
   ry=dst_y-src_y;

   h=1;
   v=1;

   if ((rx>-width) && (rx < width) && (ry>-height) && (ry<height))
   {
      if (rx>0) 
         h=-1;
      else
         h=1;
      if (ry>0) 
         v=-1;
      else
         v=1;
   }

   *h_direction=h;
   *v_direction=v;
}


#if (R2D_ASM == R2D_OFF)


static UINT32 r2d_get_pixel_value(T_R2D_GC_PTR gc,R2D_BOOLEAN foreground,INT16 x,INT16 y)
{
	UINT32 pixel_value;
	if (foreground)
	{
	 #if (R2D_DITHERING == R2D_OFF)
             pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
     #else
             pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_foreground_dithered_cache,x,y);
     #endif
	}
	else
	{
	 #if (R2D_DITHERING == R2D_OFF)
             pixel_value=((T_R2D_GC*)gc)->background_pixel_value;
     #else
             pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_background_dithered_cache,x,y);
     #endif
	}
	return(pixel_value);
}

// When foreground color is used, the source pixel
// is converted to the background or foreground color
// then dithered
static UINT32 r2d_convert_from_lcd_to_lcd(R2D_BOOLEAN use_foreground,UINT32 src,T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,INT16 x,INT16 y)
{
 if (use_foreground)
 {
	 
     UINT32 pixel_value;
	 if (IND_r2d_lcd_foreground_pixel(src,src_gc))
	   pixel_value=r2d_get_pixel_value(dst_gc,TRUE,x,y);
	 else
       pixel_value=r2d_get_pixel_value(dst_gc,FALSE,x,y);

	 return(pixel_value);
 }
 else return(src);
}

static UINT32 r2d_convert_from_color_to_color(R2D_BOOLEAN use_foreground,UINT32 src,T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,INT16 x,INT16 y)
{
 if (use_foreground)
 {
	 
     UINT32 pixel_value;
	 if (IND_r2d_color_framebuffer_foreground_pixel(src,src_gc))
	   pixel_value=r2d_get_pixel_value(dst_gc,TRUE,x,y);
	 else
       pixel_value=r2d_get_pixel_value(dst_gc,FALSE,x,y);

	 return(pixel_value);
 }
 else return(src);
}


static UINT32 r2d_convert_from_color_to_lcd(R2D_BOOLEAN use_foreground,UINT32 src,T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,INT16 x,INT16 y)
{
 if (use_foreground)
 {
	 UINT32 pixel_value;
	 if (IND_r2d_color_framebuffer_foreground_pixel(src,src_gc))
	   pixel_value=r2d_get_pixel_value(dst_gc,TRUE,x,y);
	 else
       pixel_value=r2d_get_pixel_value(dst_gc,FALSE,x,y);

	return(pixel_value);
 }
 else return(IND_r2d_color_to_lcd(src,x,y));
}

static UINT32 r2d_convert_from_lcd_to_color(R2D_BOOLEAN use_foreground,UINT32 src,T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,INT16 x,INT16 y)
{
 if (use_foreground)
 {
	 UINT32 pixel_value;
	 if (IND_r2d_lcd_foreground_pixel(src,src_gc))
	   pixel_value=r2d_get_pixel_value(dst_gc,TRUE,x,y);
	 else
       pixel_value=r2d_get_pixel_value(dst_gc,FALSE,x,y);

	 return(pixel_value);
 }
 else 
 {
	 return(IND_r2d_lcd_to_color(src));
 }
}

// FOR DEBUG
//#define dop(a,b) b

#define r2d_shift_pixel_down_and_write(dst,src) {\
               dst##value =R2D_PIXEL_DOWN_OUT(dst##value); \
               dst##value|=dop((dst##_current & R2D_PIXEL_MASK), \
               r2d_convert_from_lcd_to_lcd(use_foreground_color,\
			   src##_current & R2D_PIXEL_MASK,src_gc,dst_gc,x,y)) \
               << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH) ; \
               src##_current=R2D_PIXEL_DOWN_OUT(src##_current); \
               dst##_current=R2D_PIXEL_DOWN_OUT(dst##_current); \
               dst##counter--; \
               src##counter--; \
               if (src##counter==0) \
               { \
                 src##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 src##_current=*++p_##src##_current;  \
               } \
               if (dst##counter==0) \
               { \
                 dst##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
               } \
               }

#define r2d_shift_pixel_up_and_write(dst,src) {\
               dst##value =R2D_PIXEL_UP_OUT(dst##value); \
               dst##value |=dop( \
               (dst##_current >> ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) & R2D_PIXEL_MASK, \
              r2d_convert_from_lcd_to_lcd(use_foreground_color,\
			   (src##_current >> ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) & R2D_PIXEL_MASK, \
			   src_gc,dst_gc,x,y)); \
               src##_current=R2D_PIXEL_UP_OUT(src##_current); \
               dst##_current=R2D_PIXEL_UP_OUT(dst##_current); \
               dst##counter--; \
               src##counter--; \
               if (src##counter==0) \
               { \
                 src##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 src##_current=*--p_##src##_current;  \
               } \
               if (dst##counter==0) \
               { \
                 dst##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
               } \
               }

extern UINT32 r2d_lcd_or_operator(UINT32 old,UINT32 value);
// Requires shapes in graphic context coordinates
void           r2d_blit_lcd_to_lcd(T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,
                             T_R2D_SHAPE_PTR src_rectangle, 
							 T_R2D_SHAPE_PTR dst_rectangle,
							 R2D_BOOLEAN use_foreground_color)
{
    UINT32 *p_src,*p_dst,*p_src_current,*p_dst_current,*p_src_start,*p_dst_start;
    INT16 rect_width,rect_height,src_x,src_y,dst_x,dst_y;
    INT16 src_offset,dst_offset,src_height,dst_height;
    INT16 xnb,ynb,src_nb_rows,dst_nb_rows;
    INT16 src_dy,dst_dy,end_dst_dy,end_src_dy; // distance from word boundary
//    INT16 shift; // relative position (modulo a memory word) between both rectangles
    // in bits
    INT16 current_src_dy,current_dst_dy;
    INT16 temp,dstcounter,srccounter;


    register UINT32 dstvalue,dst_current;
    register UINT32 src_current;//srcvalue;
    INT32  h_direction,v_direction;
	INT16 x,y;
    T_R2D_DRAWING_MODE mode;
	T_R2D_DRAWING_OP dop;
	BOOLEAN compensate=TRUE;

	
    dop=((T_R2D_GC*)dst_gc)->drawing_op;

    

    {

    p_src=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->p_memory_words;
    p_dst=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words;

    rect_width=r2d_get_xmax(src_rectangle)-r2d_get_xmin(src_rectangle);
    rect_height=r2d_get_ymax(src_rectangle)-r2d_get_ymin(src_rectangle);
	if ((rect_width<=0) || (rect_height<=0))
		goto end_blit;

    mode=IND_r2d_get_drawing_mode(dst_gc);

    
    src_x=r2d_get_xmin(src_rectangle);
    src_y=r2d_get_ymin(src_rectangle);

    dst_x=r2d_get_xmin(dst_rectangle);
    dst_y=r2d_get_ymin(dst_rectangle);

    src_dy=(src_y & R2D_WORD_POSITION_MASK);
	dst_dy=(dst_y & R2D_WORD_POSITION_MASK);
	
    // Clipping convention such end_dst_dy is the first y position which must not
    // be copied at the end of a column
    //printf("dest y max=%d\n",r2d_get_ymax(dst_rectangle));
    end_dst_dy=((r2d_get_ymax(dst_rectangle)-1) & R2D_WORD_POSITION_MASK) ;
	end_src_dy=((r2d_get_ymax(src_rectangle)-1) & R2D_WORD_POSITION_MASK) ;
	
    //printf("dst_dy, end_dst_dy before reverse=%d,%d\n",dst_dy,end_dst_dy);
    // Number of rows is word containing last point - word containing first point
    // + 1

    // We remove - 1 because last PIXEL is at 1 from the frontier line
    dst_nb_rows=R2D_ALIGNED_MWLENGTH(r2d_get_ymax(dst_rectangle)-1)-R2D_ALIGNED_MWLENGTH(dst_y)+1;
    src_nb_rows=R2D_ALIGNED_MWLENGTH(r2d_get_ymax(src_rectangle)-1)-R2D_ALIGNED_MWLENGTH(src_y)+1;

    //printf("src_nb_rows %d\n",src_nb_rows);
    //printf("dst_nb_rows %d\n",dst_nb_rows);

    
    h_direction=1;
    v_direction=1;
    if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))==
       ((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer)))
      r2d_check_rectangle_overlap(src_x,src_y,dst_x,dst_y,
      rect_width,rect_height,&h_direction,&v_direction);

    //printf("h,v=%d,%d\n",h_direction,v_direction);


#if (R2D_REFRESH == R2D_VERTICAL)      
      src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->height;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->height;
#else
	  src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->width;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->width;
#endif

	  src_offset=R2D_ALIGNED_MWLENGTH(src_height);
      dst_offset=R2D_ALIGNED_MWLENGTH(dst_height);

      //printf("%08X,dst offset=%08X\n",p_dst,dst_offset);

      p_src_start=p_src
        +((src_x*src_offset+(src_y>>R2D_PIXELS_PER_MEMORY_WORD)));
      p_dst_start=p_dst
        +((dst_x*dst_offset+(dst_y>>R2D_PIXELS_PER_MEMORY_WORD)));

      xnb=rect_width;

      //printf("src start %08X contains %08X\n",p_src_start,*p_src_start);
      //printf("dst start %08X contains %08X\n",p_dst_start,*p_dst_start);

      //printf("rect_width %d\n",rect_width);
      if (h_direction==-1)
      {
		x=r2d_get_xmax(dst_rectangle)-1;
        p_src_start+=(rect_width-1)*src_offset;
        p_dst_start+=(rect_width-1)*dst_offset;
      }
	  else
         x=r2d_get_xmin(dst_rectangle);

      //printf("src start %08X contains %08X\n",p_src_start,*p_src_start);
      //printf("dst start %08X contains %08X\n",p_dst_start,*p_dst_start);

      if (v_direction==-1)
      {
        p_src_start+=src_nb_rows-1;
        p_dst_start+=dst_nb_rows-1;

        temp=src_dy;
        src_dy=end_src_dy;
        end_src_dy=temp;

        temp=dst_dy;
        dst_dy=end_dst_dy;
        end_dst_dy=temp;
      }


      //printf("src start %08X contains %08X\n",p_src_start,*p_src_start);
      //printf("dst start %08X contains %08X\n",p_dst_start,*p_dst_start);

      //printf("dst_start=%08X contains %08X\n",p_dst_start,*p_dst_start);
      while(xnb!=0)
      {
        p_dst_current=p_dst_start;
        p_src_current=p_src_start;

        //printf("xnb=%d\n",xnb);
        //printf("src start %08X contains %08X\n",p_src_start,*p_src_start);
        //printf("dst start %08X contains %08X\n",p_dst_start,*p_dst_start);


        ynb=dst_nb_rows-1;
        
        if (v_direction==-1)
        {
		   y=r2d_get_ymax(dst_rectangle) - 1;
           current_src_dy=(1<<R2D_PIXELS_PER_MEMORY_WORD)-1;
           current_dst_dy=(1<<R2D_PIXELS_PER_MEMORY_WORD)-1;
        }
        else
        {
           current_src_dy=0;
           current_dst_dy=0;
		   y=r2d_get_ymin(dst_rectangle);
        }
        
        dstcounter=(1<<R2D_PIXELS_PER_MEMORY_WORD);
        srccounter=(1<<R2D_PIXELS_PER_MEMORY_WORD);
        
        dst_current=*p_dst_current;
        src_current=*p_src_current;
	
        //printf("src_current=%08X, dst_current=%08X\n",src_current,dst_current);
        temp=0;
        //printf("new column\n dst=%08X\n",p_dst_current);
        //printf("current_dst_dy =%d, dst_dy=%d\n",current_dst_dy,dst_dy);
        dstvalue=0;
		if (v_direction==-1)
		{
			while(current_dst_dy!=dst_dy)
			{
                r2d_shift_pixel_up(dstvalue,dst_current,dstcounter,p_dst_current);
                current_dst_dy--;
                //printf("dstcounter=%d\n",dstcounter);
			    y--;
			}
			while(current_src_dy!=src_dy)
			{
            
              //printf("current_src_dy=%d\n",current_src_dy);
               //printf("srccounter=%d\n",srccounter);

              r2d_shift_pixel_up(temp,src_current,srccounter,p_src_current);
              current_src_dy--;
              //printf("src_current=%08X\n",src_current);
			  
            
			}
			while(ynb!=0)
			{
            
              r2d_shift_pixel_up_and_write(dst,src);
              //printf("srccounter=%d\n",srccounter);
			  y--;
            
              if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
			  {
               ynb--;
               
			   *p_dst_current--=dstvalue;

#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
         if ((p_dst_current<((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words) 
         || (p_dst_current>((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_frame_buffer_end))
         {
              //printf("Error : frame_buffer overflow\n");
			  IND_rvf_send_trace("R2D : Framebuffer overflow1",27, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
         }
#endif
#endif

               current_dst_dy=(1<<R2D_PIXELS_PER_MEMORY_WORD)-1;
               
               dst_current=*p_dst_current;  
                    
               //printf("%08X <- %08X\n",p_dst_current,dstvalue);

               dstvalue=0;
			  }
            
			}
			current_dst_dy++;
			while(current_dst_dy!=end_dst_dy)
			{
            
              r2d_shift_pixel_up_and_write(dst,src);
              current_dst_dy--;
              //printf("Last row %08X, %08X\n",p_dst_current,current_dst_dy);
			  y--;
            
			}
			if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
               compensate=FALSE;
            while(dstcounter!=(1<<R2D_PIXELS_PER_MEMORY_WORD))
			{
             
                 r2d_shift_pixel_up(dstvalue,dst_current,dstcounter,p_dst_current);
                 current_dst_dy--;
                 //printf("   Last row %08X\n",p_src_current);
                 //printf("dstcounter=%d\n",dstcounter);
                 y--;

             

			}
			if (compensate==TRUE)
			{
			 *++p_dst_current=dstvalue;
          
			}
            else
			{
			 *p_dst_current=dstvalue;
           
			}
#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
         if ((p_dst_current<((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words) 
         || (p_dst_current>((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_frame_buffer_end))
         {
              //printf("Error : frame_buffer overflow\n");
			  IND_rvf_send_trace("R2D : Framebuffer overflow2",27, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
         }
#endif
#endif

        
		}
		else
		{
			while(current_dst_dy!=dst_dy)
			{
              r2d_shift_pixel_down(dstvalue,dst_current,dstcounter,p_dst_current);
              current_dst_dy++;
			  y++;
              //printf("dstcounter=%d\n",dstcounter);
            }
			while(current_src_dy!=src_dy)
			{
            
              r2d_shift_pixel_down(temp,src_current,srccounter,p_src_current);
              current_src_dy++;
			  
            
			}
			while(ynb!=0)
			{
            
              r2d_shift_pixel_down_and_write(dst,src);
			  y++;
            
              if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
			  {
                 ynb--;
               
        
               *p_dst_current++=dstvalue;
#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
         if ((p_dst_current<((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words) 
         || (p_dst_current>((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_frame_buffer_end))
         {
			 char error[256];
			 T_R2D_RECT *dst;

			 //dst=(T_R2D_RECT*)dst_rectangle;
			 //sprintf(error,"%d %d %d %d",dst->ul_x,dst->ul_y,
			//	 dst->br_x,dst->br_y);
			 //IND_rvf_send_trace(error,strlen(error), NULL_PARAM, 
			//	   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
              //printf("Error : frame_buffer overflow\n");
			  IND_rvf_send_trace("R2D : Framebuffer overflow3",27, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
         }
#endif
#endif

                 current_dst_dy=0;
               
                 dst_current=*p_dst_current;  
                    
               //printf("%08X <- %08X\n",p_dst_current,dstvalue);

                 dstvalue=0;
			  }
            
			}
			
            current_dst_dy--;
			while(current_dst_dy!=end_dst_dy)
			{
            
              r2d_shift_pixel_down_and_write(dst,src);
              current_dst_dy++;
              //printf("Last row %08X\n",p_dst_current);
			  y++;
            
			}
			if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
              compensate=FALSE;
            while(dstcounter!=(1<<R2D_PIXELS_PER_MEMORY_WORD))
			{
             
                 r2d_shift_pixel_down(dstvalue,dst_current,dstcounter,p_dst_current);
                 current_dst_dy++;
                 //printf("Last row %08X\n",p_dst_current);
				 y++;
             
			}
			if (compensate==TRUE)
			{
				*--p_dst_current=dstvalue;
			}
            else
			{
				*p_dst_current=dstvalue;
			}
#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
         if ((p_dst_current<((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words) 
         || (p_dst_current>((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_frame_buffer_end))
         {
              //printf("Error : frame_buffer overflow\n");
			  IND_rvf_send_trace("R2D : Framebuffer overflow4",27, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
         }
#endif
#endif

		}

        
        dstvalue=0;
        
          
        if (h_direction==-1)
        {
          p_src_start-=src_offset;
          p_dst_start-=dst_offset;
		  x--;
        }
        else
        {
          p_src_start+=src_offset;
          p_dst_start+=dst_offset;
		  x++;
        }

        xnb--;
      }

      
      
    
  }
end_blit: dstvalue=0;
}


#undef r2d_shift_pixel_down_and_write
#undef r2d_shift_pixel_up_and_write

#define r2d_shift_pixel_down_and_write(dst,src) {\
               dst##value =R2D_PIXEL_DOWN_OUT(dst##value); \
               dst##value|=dop((dst##_current & R2D_PIXEL_MASK), \
               r2d_convert_from_color_to_color(use_foreground_color,\
			   src##_current & R2D_PIXEL_MASK,src_gc,dst_gc,x,y)) \
               << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH) ; \
               src##_current=R2D_PIXEL_DOWN_OUT(src##_current); \
               dst##_current=R2D_PIXEL_DOWN_OUT(dst##_current); \
               dst##counter--; \
               src##counter--; \
               if (src##counter==0) \
               { \
                 src##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 src##_current=*++p_##src##_current;  \
               } \
               if (dst##counter==0) \
               { \
                 dst##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
               } \
               }

#define r2d_shift_pixel_up_and_write(dst,src) {\
               dst##value =R2D_PIXEL_UP_OUT(dst##value); \
               dst##value |=dop( \
               (dst##_current >> ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) & R2D_PIXEL_MASK, \
               r2d_convert_from_color_to_color(use_foreground_color,\
			   (src##_current >> ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) & R2D_PIXEL_MASK, \
			   src_gc,dst_gc,x,y)); \
               src##_current=R2D_PIXEL_UP_OUT(src##_current); \
               dst##_current=R2D_PIXEL_UP_OUT(dst##_current); \
               dst##counter--; \
               src##counter--; \
               if (src##counter==0) \
               { \
                 src##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 src##_current=*--p_##src##_current;  \
               } \
               if (dst##counter==0) \
               { \
                 dst##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
               } \
               }



// Requires shapes in graphic context coordinates
void           r2d_blit_color_to_color(T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,
                             T_R2D_SHAPE_PTR src_rectangle, 
							 T_R2D_SHAPE_PTR dst_rectangle,
							 R2D_BOOLEAN use_foreground_color)
{
    UINT32 *p_src,*p_dst,*p_src_current,*p_dst_current,*p_src_start,*p_dst_start,value;
    INT16 rect_width,rect_height,src_x,src_y,dst_x,dst_y;
    INT16 src_offset,dst_offset,src_height,dst_height;
    INT16 xnb,ynb,nb_rows;
    INT16 x,y;//,temp;


    INT32  h_direction,v_direction;
    T_R2D_DRAWING_MODE mode;
    T_R2D_DRAWING_OP dop;
	

    dop=((T_R2D_GC*)dst_gc)->drawing_op;

    

    {

    p_src=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->p_memory_words;
    p_dst=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words;

    rect_width=r2d_get_xmax(src_rectangle)-r2d_get_xmin(src_rectangle);
    rect_height=r2d_get_ymax(src_rectangle)-r2d_get_ymin(src_rectangle);

	if ((rect_width<=0) || (rect_height<=0))
		goto end_blit_c;

    mode=IND_r2d_get_drawing_mode(dst_gc);

    
    src_x=r2d_get_xmin(src_rectangle);
    src_y=r2d_get_ymin(src_rectangle);

    dst_x=r2d_get_xmin(dst_rectangle);
    dst_y=r2d_get_ymin(dst_rectangle);


    // Number of rows is word containing last point - word containing first point
    // + 1
    nb_rows=(r2d_get_ymax(dst_rectangle)-1)-(dst_y)+1;
    //printf("nb_rows %d\n",nb_rows);
    
    h_direction=1;
    v_direction=1;
    if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))==
       ((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer)))
      r2d_check_rectangle_overlap(src_x,src_y,dst_x,dst_y,
      rect_width,rect_height,&h_direction,&v_direction);

    //printf("h,v=%d,%d\n",h_direction,v_direction);


 #if (R2D_REFRESH == R2D_VERTICAL)      
      src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->height;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->height;
#else
	  src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->width;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->width;
#endif

      src_offset=(src_height);
      dst_offset=(dst_height);

      //printf("%08X,dst offset=%08X\n",p_dst,dst_offset);

      p_src_start=p_src
        +((src_x*src_offset+(src_y)));
      p_dst_start=p_dst
        +((dst_x*dst_offset+(dst_y)));

      xnb=rect_width;

      //printf("start %08X contains %08X\n",p_dst_start,*p_dst_start);

      if (h_direction==-1)
      {
		x=r2d_get_xmax(dst_rectangle)-1;
        p_src_start+=(rect_width-1)*src_offset;
        p_dst_start+=(rect_width-1)*dst_offset;
      }
	  else
		x=r2d_get_xmin(dst_rectangle);

      if (v_direction==-1)
      {
        p_src_start+=nb_rows-1;
        p_dst_start+=nb_rows-1;

      }

      //printf("dst_start=%08X contains %08X\n",p_dst_start,*p_dst_start);
      while(xnb!=0)
      {
        p_dst_current=p_dst_start;
        p_src_current=p_src_start;

        ynb=nb_rows; // Not using - 1 since not different processing of ending word
        // (which is here a pixel instead of being only a memory word)
        
        
        
        //printf("src_current=%08X, dst_current=%08X\n",src_current,dst_current);
        //printf("new column\n dst=%08X\n",p_dst_current);
        
		if (v_direction==-1)
		{
			while(ynb!=0)
			{
            
              value=*p_dst_current;
              *p_dst_current--=dop(value,*p_src_current--);
			  y--;
            
              ynb--;
			}
		}
		else
		{
			while(ynb!=0)
			{
            
              value=*p_dst_current;
              *p_dst_current++=dop(value,*p_src_current++);
			  y++;
           
              ynb--;
			}
		}

        
          
        if (h_direction==-1)
        {
          p_src_start-=src_offset;
          p_dst_start-=dst_offset;
		  x--;
        }
        else
        {
          p_src_start+=src_offset;
          p_dst_start+=dst_offset;
		  x++;
        }

        xnb--;
      }

      
      
   
  }
end_blit_c:ynb=0; 
}


#undef r2d_shift_pixel_down_and_write
#undef r2d_shift_pixel_up_and_write

#define r2d_shift_pixel_down_and_write(dst,src) {\
               dst##value =r2d_convert_from_lcd_to_color(use_foreground_color,\
			   src##_current & R2D_PIXEL_MASK,src_gc,dst_gc,x,y); \
               dst##value =dop(*p_dst_current,dst##value); \
               *p_##dst##_current++=dst##value;\
               src##_current=R2D_PIXEL_DOWN_OUT(src##_current); \
               src##counter--; \
               if (src##counter==0) \
               { \
                 src##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 src##_current=*++p_##src##_current;  \
               } \
               }


#define r2d_shift_pixel_up_and_write(dst,src) {\
               dst##value =r2d_convert_from_lcd_to_color(use_foreground_color,\
			   src##_current & R2D_PIXEL_MASK,src_gc,dst_gc,x,y); \
               dst##value =dop(*p_dst_current,dst##value); \
               *p_##dst##_current--=dst##value;\
               src##_current=R2D_PIXEL_UP_OUT(src##_current); \
               src##counter--; \
               if (src##counter==0) \
               { \
                 src##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
                 src##_current=*--p_##src##_current;  \
               } \
               }

// Requires shapes in graphic context coordinates
void           r2d_blit_lcd_to_color(T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,
                             T_R2D_SHAPE_PTR src_rectangle, 
							 T_R2D_SHAPE_PTR dst_rectangle,
							 R2D_BOOLEAN use_foreground_color)
{
    UINT32 *p_src,*p_dst,*p_src_current,*p_dst_current,*p_src_start,*p_dst_start;
    INT16 rect_width,rect_height,src_x,src_y,dst_x,dst_y;
    INT16 src_offset,dst_offset,src_height,dst_height;
    INT16 xnb,ynb,src_nb_rows,dst_nb_rows;
    INT16 src_dy,dst_dy,end_dst_dy,end_src_dy; // distance from word boundary
//    INT16 shift; // relative position (modulo a memory word) between both rectangles
    // in bits
    INT16 current_src_dy;//,current_dst_dy;
    INT16 temp,srccounter;//,dstcounter;


    register UINT32 dstvalue;//,dst_current;
    register UINT32 src_current;//,srcvalue;
    INT32  h_direction,v_direction;
	INT16 x,y;
    T_R2D_DRAWING_MODE mode;
	T_R2D_DRAWING_OP dop;

    dop=((T_R2D_GC*)dst_gc)->drawing_op;


    

    {

    p_src=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->p_memory_words;
    p_dst=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words;

    rect_width=r2d_get_xmax(src_rectangle)-r2d_get_xmin(src_rectangle);
    rect_height=r2d_get_ymax(src_rectangle)-r2d_get_ymin(src_rectangle);

	if ((rect_width<=0) || (rect_height<=0))
		goto end_blit_d;

    mode=IND_r2d_get_drawing_mode(dst_gc);

    
    src_x=r2d_get_xmin(src_rectangle);
    src_y=r2d_get_ymin(src_rectangle);

    dst_x=r2d_get_xmin(dst_rectangle);
    dst_y=r2d_get_ymin(dst_rectangle);

    src_dy=src_y & R2D_WORD_POSITION_MASK;
	dst_dy=dst_y & R2D_WORD_POSITION_MASK;
	
    // Clipping convention such end_dst_dy is the first y position which must not
    // be copied at the end of a column
    end_dst_dy=(r2d_get_ymax(dst_rectangle)-1) & R2D_WORD_POSITION_MASK;
	end_src_dy=(r2d_get_ymax(src_rectangle)-1) & R2D_WORD_POSITION_MASK ;
	
    // Number of rows is word containing last point - word containing first point
    // + 1
    src_nb_rows=R2D_ALIGNED_MWLENGTH(r2d_get_ymax(src_rectangle)-1)-R2D_ALIGNED_MWLENGTH(src_y) + 1;
    
    dst_nb_rows=(r2d_get_ymax(dst_rectangle))-(dst_y);
    //printf("nb_rows %d\n",nb_rows);
    
    h_direction=1;
    v_direction=1;
    if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))==
       ((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer)))
      r2d_check_rectangle_overlap(src_x,src_y,dst_x,dst_y,
      rect_width,rect_height,&h_direction,&v_direction);

    //printf("h,v=%d,%d\n",h_direction,v_direction);


      
#if (R2D_REFRESH == R2D_VERTICAL)      
      src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->height;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->height;
#else
	  src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->width;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->width;
#endif
   
      src_offset=R2D_ALIGNED_MWLENGTH(src_height);
      dst_offset=dst_height;

      //printf("%08X,dst offset=%08X\n",p_dst,dst_offset);

      p_src_start=p_src
        +((src_x*src_offset+(src_y>>R2D_PIXELS_PER_MEMORY_WORD)));
      p_dst_start=p_dst
        +((dst_x*dst_offset+(dst_y)));

      xnb=rect_width;

      //printf("start %08X contains %08X\n",p_dst_start,*p_dst_start);

      if (h_direction==-1)
      {
		x=r2d_get_xmax(dst_rectangle)-1;
        p_src_start+=(rect_width-1)*src_offset;
        p_dst_start+=(rect_width-1)*dst_offset;
      }
	  else
		  x=r2d_get_xmin(dst_rectangle);

      if (v_direction==-1)
      {
        p_src_start+=src_nb_rows-1;
        p_dst_start+=dst_nb_rows-1;

        temp=src_dy;
        src_dy=end_src_dy;
        end_src_dy=temp;

      }

      //printf("dst_start=%08X contains %08X\n",p_dst_start,*p_dst_start);
      while(xnb!=0)
      {
        p_dst_current=p_dst_start;
        p_src_current=p_src_start;

        ynb=dst_nb_rows; // No -1 since no different processing for last word
        
        if (v_direction==-1)
        {
           current_src_dy=(1<<R2D_PIXELS_PER_MEMORY_WORD)-1;
		   y=r2d_get_ymax(dst_rectangle)-1;
        }
        else
        {
           current_src_dy=0;
		   y=r2d_get_ymin(dst_rectangle);
        }
        
        srccounter=(1<<R2D_PIXELS_PER_MEMORY_WORD);
        
        src_current=*p_src_current;
        //printf("src_current=%08X, dst_current=%08X\n",src_current,dst_current);
        temp=0;
        //printf("new column\n dst=%08X\n",p_dst_current);
        
        //printf("src_dy=%d\n",src_dy);

		if (v_direction==-1)
		{
			while(current_src_dy!=src_dy)
			{
            
              //printf("current_src_dy=%d\n",current_src_dy);
              r2d_shift_pixel_up(temp,src_current,srccounter,p_src_current);
              current_src_dy--;
			  
              //printf("src_current=%08X\n",src_current);
            
			}
			//printf("src_current=%08X, dst_current=%08X, dstvalue=%08X\n dstcounter=%08X, srccounter=%08X\n",
        //src_current,dst_current,dstvalue,dstcounter,srccounter);
            while(ynb!=0)
			{
            
              r2d_shift_pixel_up_and_write(dst,src);
			  y--;
            
              ynb--;

			}
		}
		else
		{
			while(current_src_dy!=src_dy)
			{
            
              r2d_shift_pixel_down(temp,src_current,srccounter,p_src_current);
              current_src_dy++;
			  
            
			}
			//printf("src_current=%08X, dst_current=%08X, dstvalue=%08X\n dstcounter=%08X, srccounter=%08X\n",
        //src_current,dst_current,dstvalue,dstcounter,srccounter);
           while(ynb!=0)
		   {
            
              r2d_shift_pixel_down_and_write(dst,src);
			  y++;
            
            ynb--;

		   }
		}

        
        
        
          
        if (h_direction==-1)
        {
          p_src_start-=src_offset;
          p_dst_start-=dst_offset;
		  x--;
        }
        else
        {
          p_src_start+=src_offset;
          p_dst_start+=dst_offset;
		  x++;
        }

        xnb--;
      }

      
      
    
  }
end_blit_d:ynb=0;
}



#undef r2d_shift_pixel_down_and_write
#undef r2d_shift_pixel_up_and_write

#define r2d_shift_pixel_down_and_write(dst,src) {\
               dst##value =R2D_PIXEL_DOWN_OUT(dst##value); \
               src##_current=r2d_convert_from_color_to_lcd(use_foreground_color,\
			   *p_##src##_current++,src_gc,dst_gc,x,y); \
               dst##value|=dop((dst##_current & R2D_PIXEL_MASK), \
               src##_current) \
               << ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH) ; \
               dst##_current=R2D_PIXEL_DOWN_OUT(dst##_current); \
               dst##counter--; \
               if (dst##counter==0) \
               { \
                 dst##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
               } \
               }


#define r2d_shift_pixel_up_and_write(dst,src) {\
               dst##value =R2D_PIXEL_UP_OUT(dst##value); \
               src##_current=r2d_convert_from_color_to_lcd(use_foreground_color,\
			   *p_##src##_current--,src_gc,dst_gc,x,y); \
               dst##value |=dop( \
               (dst##_current >> ((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH)) & R2D_PIXEL_MASK, \
               src##_current); \
               dst##_current=R2D_PIXEL_UP_OUT(dst##_current); \
               dst##counter--; \
               if (dst##counter==0) \
               { \
                 dst##counter=(1<<R2D_PIXELS_PER_MEMORY_WORD); \
               } \
               }

// Requires shapes in graphic context coordinates
void           r2d_blit_color_to_lcd(T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,
                             T_R2D_SHAPE_PTR src_rectangle, 
							 T_R2D_SHAPE_PTR dst_rectangle,
							 R2D_BOOLEAN use_foreground_color)
{
    UINT32 *p_src,*p_dst,*p_src_current,*p_dst_current,*p_src_start,*p_dst_start;
    INT16 rect_width,rect_height,src_x,src_y,dst_x,dst_y;
    INT16 src_offset,dst_offset,src_height,dst_height;
    INT16 xnb,ynb,dst_nb_rows,src_nb_rows;
    INT16 src_dy,dst_dy,end_dst_dy,end_src_dy; // distance from word boundary
//    INT16 shift; // relative position (modulo a memory word) between both rectangles
    // in bits
    INT16 current_dst_dy;//,current_src_dy;
    INT16 temp,dstcounter,srccounter;


    register UINT32 dstvalue,dst_current;
    register UINT32 src_current;//,srcvalue;
    INT32  h_direction,v_direction;
	INT16 x,y;
    T_R2D_DRAWING_MODE mode;
    T_R2D_DRAWING_OP dop;
	BOOLEAN compensate=TRUE;

    dop=((T_R2D_GC*)dst_gc)->drawing_op;


    

     {

    p_src=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->p_memory_words;
    p_dst=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->p_memory_words;

    rect_width=r2d_get_xmax(src_rectangle)-r2d_get_xmin(src_rectangle);
    rect_height=r2d_get_ymax(src_rectangle)-r2d_get_ymin(src_rectangle);

	if ((rect_width<=0) || (rect_height<=0))
		goto end_blit_e;

    mode=IND_r2d_get_drawing_mode(dst_gc);

    
    src_x=r2d_get_xmin(src_rectangle);
    src_y=r2d_get_ymin(src_rectangle);

    dst_x=r2d_get_xmin(dst_rectangle);
    dst_y=r2d_get_ymin(dst_rectangle);

    src_dy=src_y & R2D_WORD_POSITION_MASK;
	dst_dy=dst_y & R2D_WORD_POSITION_MASK;
	
    // Clipping convention such end_dst_dy is the first y position which must not
    // be copied at the end of a column
    end_dst_dy=(r2d_get_ymax(dst_rectangle)-1) & R2D_WORD_POSITION_MASK ;
	end_src_dy=(r2d_get_ymax(src_rectangle)-1) & R2D_WORD_POSITION_MASK ;
	
    // Number of rows is word containing last point - word containing first point
    // + 1
    dst_nb_rows=R2D_ALIGNED_MWLENGTH(r2d_get_ymax(dst_rectangle)-1)-R2D_ALIGNED_MWLENGTH(dst_y) + 1;
    src_nb_rows=(r2d_get_ymax(src_rectangle))-(src_y);

    //printf("src_nb_rows %d\n",src_nb_rows);
    //printf("dst_nb_rows %d\n",dst_nb_rows);
    
    h_direction=1;
    v_direction=1;
    if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))==
       ((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer)))
      r2d_check_rectangle_overlap(src_x,src_y,dst_x,dst_y,
      rect_width,rect_height,&h_direction,&v_direction);

    //printf("h,v=%d,%d\n",h_direction,v_direction);



       
#if (R2D_REFRESH == R2D_VERTICAL)      
      src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->height;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->height;
#else
	  src_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->width;
      dst_height=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->width;
#endif
        
      src_offset=src_height;
      dst_offset=R2D_ALIGNED_MWLENGTH(dst_height);

      //printf("%08X,dst offset=%08X\n",p_dst,dst_offset);

      p_src_start=p_src
        +((src_x*src_offset+(src_y)));
      p_dst_start=p_dst
        +((dst_x*dst_offset+(dst_y>>R2D_PIXELS_PER_MEMORY_WORD)));

      xnb=rect_width;

      //printf("start %08X contains %08X\n",p_dst_start,*p_dst_start);

      if (h_direction==-1)
      {
        x=r2d_get_xmax(dst_rectangle)-1;
        p_src_start+=(rect_width-1)*src_offset;
        p_dst_start+=(rect_width-1)*dst_offset;
      }
      else
        x=r2d_get_xmin(dst_rectangle);

      if (v_direction==-1)
      {
        p_src_start+=src_nb_rows-1;
        p_dst_start+=dst_nb_rows-1;

        temp=dst_dy;
        dst_dy=end_dst_dy;
        end_dst_dy=temp;
      }
      

      //printf("dst_start=%08X contains %08X\n",p_dst_start,*p_dst_start);
      while(xnb!=0)
      {
        p_dst_current=p_dst_start;
        p_src_current=p_src_start;

        ynb=dst_nb_rows-1;
        
        if (v_direction==-1)
        {
           y=r2d_get_ymax(dst_rectangle) - 1;
           current_dst_dy=(1<<R2D_PIXELS_PER_MEMORY_WORD)-1;
        }
        else
        {
           current_dst_dy=0;
           y=r2d_get_ymin(dst_rectangle);
        }
        
        dstcounter=(1<<R2D_PIXELS_PER_MEMORY_WORD);
        srccounter=(1<<R2D_PIXELS_PER_MEMORY_WORD);
        
        dst_current=*p_dst_current;
        //printf("src_current=%08X, dst_current=%08X\n",src_current,dst_current);
        temp=0;
        //printf("new column\n dst=%08X\n",p_dst_current);
        dstvalue=0;
        //printf("current_dst_dy=%08X,dst_dy=%08X\n",current_dst_dy,dst_dy);

		if (v_direction==-1)
		{
			 while(current_dst_dy!=dst_dy)
			 {
            
              r2d_shift_pixel_up(dstvalue,dst_current,dstcounter,p_dst_current);
              current_dst_dy--;
              y--;
              //printf("dstcounter=%d\n",dstcounter);
            
			 }
			 while(ynb!=0)
			 {
            
              r2d_shift_pixel_up_and_write(dst,src);
              y--;
            
              if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
			  {
                ynb--;
               
               
               
                 *p_dst_current--=dstvalue;
                  current_dst_dy=(1<<R2D_PIXELS_PER_MEMORY_WORD)-1;
               
                  dst_current=*p_dst_current;  
                    
               //printf("%08X <- %08X\n",p_dst_current,dstvalue);

                  dstvalue=0;
			  }
            
			 }
			    current_dst_dy++;

			while(current_dst_dy!=end_dst_dy)
			{
            
              r2d_shift_pixel_up_and_write(dst,src);
              current_dst_dy--;
              y--;
              //printf("Last row %08X, %08X\n",p_dst_current,current_dst_dy);
            
			}
			if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
               compensate=FALSE;
           while(dstcounter!=(1<<R2D_PIXELS_PER_MEMORY_WORD))
		   {
             
                 r2d_shift_pixel_up(dstvalue,dst_current,dstcounter,p_dst_current);
                 current_dst_dy--;
                 //printf("Last row %08X\n",p_dst_current);
                 //printf("dstcounter=%d\n",dstcounter);
                 y--;

             

		   }
		   if (compensate==TRUE)
		   {
             *++p_dst_current=dstvalue;
            
		   }
           else
		   {
             *p_dst_current=dstvalue;
             
		   }
        
		}
		else
		{
			while(current_dst_dy!=dst_dy)
			{
            
              r2d_shift_pixel_down(dstvalue,dst_current,dstcounter,p_dst_current);
              current_dst_dy++;
              y++;
              //printf("dstcounter=%d\n",dstcounter);
            
            }
			while(ynb!=0)
			{
            
              r2d_shift_pixel_down_and_write(dst,src);
              y++;
            
              if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
			  {
               ynb--;
               
               
               
               
                *p_dst_current++=dstvalue;
                current_dst_dy=0;
               
                dst_current=*p_dst_current;  
                    
               //printf("%08X <- %08X\n",p_dst_current,dstvalue);

                dstvalue=0;
			  }
            
			}
			current_dst_dy--;
        
           while(current_dst_dy!=end_dst_dy)
		   {
            
              r2d_shift_pixel_down_and_write(dst,src);
              current_dst_dy++;
              y++;
              //printf("Last row %08X\n",p_dst_current);
            
		   }
		   if (dstcounter==(1<<R2D_PIXELS_PER_MEMORY_WORD))
             compensate=FALSE;
          while(dstcounter!=(1<<R2D_PIXELS_PER_MEMORY_WORD))
		  {
             
                 r2d_shift_pixel_down(dstvalue,dst_current,dstcounter,p_dst_current);
                 current_dst_dy++;
                 //printf("Last row %08X\n",p_dst_current);
                 y++;
             

		  }
		   if (compensate==TRUE)
		  {
            *--p_dst_current=dstvalue;
		  }
          else
		  {
            *p_dst_current=dstvalue;
		  }
		}

        
        //printf("src_current=%08X, dst_current=%08X, dstvalue=%08X\n dstcounter=%08X, srccounter=%08X\n",
        //src_current,dst_current,dstvalue,dstcounter,srccounter);
        
        // One need a different processing for last word
        //printf("Last row %08X,end_dst_dy=%08X,current_dy=%08X\n",p_dst_current,end_dst_dy,current_dst_dy);
        
            
        //end_dst_dy MUST be copied
        // It is at 1 from the copy bit rectangle frontier
        
        
        
        //printf("dstvalue: %08X <- %08X\n",p_dst_current,dstvalue);
        
        dstvalue=0;
        
          
        if (h_direction==-1)
        {
          x--;
          p_src_start-=src_offset;
          p_dst_start-=dst_offset;
        }
        else
        {
          x++;
          p_src_start+=src_offset;
          p_dst_start+=dst_offset;
        }

        xnb--;
      }

      
      
    
  }
end_blit_e:dstvalue=0;
}

#endif

/*********************

  R2D ASM MODE

**********************/

#if (R2D_ASM == R2D_ON)

#define R2D_BRANCH_INST 0xFF000000

/*
Patch a block of 3 instructions with a block defined
by the user. The block does not contain any branch instruction.
The branch must use a special syntax introduced by the long word
R2D_BRANCH_INST
*/
void r2d_patch_code_block(UINT32* src,UINT32 *dst)
{
  

    if (*src == R2D_BRANCH_INST)
    {
       *dst++ = *(&r2d_start_branch_inst);
       src++;
       // PC is ahead of 8 bytes of current instruction because of prefetch
       // So -8 must be used
       *dst = (((((*src) - ((UINT32)dst)) - 8)>>2) & 0x0FFFFFF) | 0xEB000000;
       *++dst= *(&r2d_stop_branch_inst);
    }
    else
    {
       
       *dst++=*src++;
       *dst++=*src++;
       *dst++=*src++;
    }
}

/*
Copy one instruction of code
*/
void r2d_patch_inst(UINT32* src,UINT32 *dst)
{
  *dst++ = *src++;
}


/*
Patch the sequence of instructions reading the foreground 
background colors. It copies a sequence containing
two LDR and update the LDR offsets
*/
void r2d_patch_get_color(UINT32* src,UINT32 *dst)
{
       UINT32 r,offset;
       INT16 delta;

       delta=(((INT32)src-(INT32)dst));

       r=*src++;
       offset=r & 0xFFF;
       offset+=delta;
       offset=offset & 0xFFF;
       *dst++ = (r & 0xFFFFF000) | offset;
       
       r=*src++;
       offset=r & 0xFFF;
       offset+=delta;
       offset=offset & 0xFFF;
       *dst++ = (r & 0xFFFFF000) | offset;

      *dst++ = *src++;
}

/*
Patch with a branch if f is true or add a NOP
*/
void r2d_patch_branch(UINT32 *src,UINT32 *dst,BOOLEAN f)
{
  INT32 offset;
  if (f)
  {
     offset=(((((INT32)dst-(INT32)src))-8)>>2) & 0x00FFFFFF;
     *src=(0xEA<<24) | offset;
  }
  else
  {
     *src=0xe1a0b00b;
  }
}


/*
Replace the shift value by another one
*/
#define R2D_MOV_OPCODE 0xD
void r2d_patch_shift(UINT32 *src,UINT32 shift,INT16 left)
{
  UINT32 data;
  
  data=*src;


  // Shift addressing by default
  data=data  & 0xFDFFFFFF  ;

  
  if ((shift !=0) && (shift != 32))
  {
	 data=data & 0xFFFFF00F;
	 if (left==1)
        data=data|(((shift&0x01F)<<7)&0x0F80); // LSL
	 else
        data=data|(((shift&0x01F)<<7)&0x0F80)| 0x20; // LSR
  }
  else if (shift != 32)
  {
     data=data & 0xFFFFF00F;
     data=data|(((shift&0x01F)<<7)&0x0F80); // LSL 0
	
  }
  else
  {
     data=(data & 0xFFFFF07F); // LSR 0
	  
  }
  *src=data;
}

void r2d_patch_moveshift(UINT32 *src,UINT32 shift,INT16 left)
{
  UINT32 data;
  UINT32 dstreg;
  UINT32 opcode;

  data=*src;

  dstreg=(data & 0x0F000);
  dstreg=dstreg>>12;

  opcode=data & 0x01E00000;
  opcode=opcode>>21;
  if (opcode!=R2D_MOV_OPCODE)
	  dstreg=0;

  // Shift addressing by default
  data=data  & 0xF1FFFFFF  ;

  
  if ((shift !=0) && (shift != 32))
  {
	 if (opcode==R2D_MOV_OPCODE)
        data=data & 0xFFFFF000;
	 else
        data=data & 0xFFFFF00F;
	 if (left==1)
        data=data|(((shift&0x01F)<<7)&0x0F80)|dstreg; // LSL
	 else
        data=data|(((shift&0x01F)<<7)&0x0F80)| 0x20|dstreg; // LSR
  }
  else if (shift != 32)
  {
     if (opcode==R2D_MOV_OPCODE)
        data=data & 0xFFFFF000;
	 else
        data=data & 0xFFFFF00F;
     data=data|(((shift&0x01F)<<7)&0x0F80)|dstreg; // LSL 0
	
  }
  else
  {
     //data=(data & 0xFFFFF07F); // LSR 32
	  data=(data & 0xFFFFF000) | 0x02000000; // LSR 32
	  
  }
  *src=data;
}
/*
Patch the const table contained in the .text section
with the new foreground and background values
*/
void r2d_patch_color_conversion(T_R2D_GC_PTR gc)
{
  UINT32 *p;
  
  p=&r2d_blit_foreground;
  *p=((T_R2D_GC*)gc)->foreground_pixel_value;
  
  p=&r2d_blit_background;
  *p=((T_R2D_GC*)gc)->background_pixel_value;
  
}

void r2d_patch_blit(T_R2D_GC_PTR dst_gc,T_R2D_DRAWING_MODE mode,
					R2D_BOOLEAN use_foreground_color,INT32 srcdst)
{
	// Patch mode
	
extern R2D_BOOLEAN r2d_g_old_use_foreground;
extern INT32 r2d_g_old_srcdst;

    if (r2d_g_old_mode != mode)
	{
		r2d_g_old_mode=mode;
	    r2d_patch_code_block(r2d_get_asm_drawing_op(dst_gc,mode),&r2d_sb_down1);
        r2d_patch_code_block(r2d_get_asm_drawing_op(dst_gc,mode),&r2d_sb_down2);
        r2d_patch_code_block(r2d_get_asm_drawing_op(dst_gc,mode),&r2d_sa_up1);
        r2d_patch_code_block(r2d_get_asm_drawing_op(dst_gc,mode),&r2d_sa_up2);
	}

    // Meaning of variables names
    // Last word is [ab]_(down1|down2|up1|up2)
    // a or b is the blit version (blit_a oe blit_b)
    // down described which version of the macro is used
    // (down or up one) and the number is used to differentiate
    // the calls to the macro

    // For the prefix, sft_ is for part of the code where a shift must be
    // patched. For instance: sft_dst_n_a_up1
    // The second part says if the shift is for a src, dst or other
    // n means noraml shift like R2D_PIXEL_DEPTH
    // The n means complementd for shift as (1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH

	// Patch color detection
	if (r2d_g_old_use_foreground != use_foreground_color)
	{
		r2d_g_old_use_foreground=use_foreground_color;
        if (use_foreground_color)
		{
		    if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC *)dst_gc)->p_frame_buffer))->kind!=R2D_FULL_KIND)
			{
               r2d_patch_code_block(&r2d_lcd_start_foreground_pixel,&r2d_sdb_down1);
               r2d_patch_code_block(&r2d_lcd_start_foreground_pixel,&r2d_sdb_down2);
               r2d_patch_code_block(&r2d_lcd_start_foreground_pixel,&r2d_sda_up1);
               r2d_patch_code_block(&r2d_lcd_start_foreground_pixel,&r2d_sda_up2);
			}
		    else
			{
			   r2d_patch_code_block(&r2d_color_start_foreground_pixel,&r2d_sdb_down1);
               r2d_patch_code_block(&r2d_color_start_foreground_pixel,&r2d_sdb_down2);
               r2d_patch_code_block(&r2d_color_start_foreground_pixel,&r2d_sda_up1);
               r2d_patch_code_block(&r2d_color_start_foreground_pixel,&r2d_sda_up2);
			}

            r2d_patch_color_conversion(dst_gc);
			r2d_g_old_foreground_pixelvalue=((T_R2D_GC*)dst_gc)->foreground_pixel_value;
            r2d_g_old_background_pixelvalue=((T_R2D_GC*)dst_gc)->background_pixel_value;


            r2d_patch_get_color(&r2d_start_get_color,&r2d_scb_down1);
            r2d_patch_get_color(&r2d_start_get_color,&r2d_scb_down2);
            r2d_patch_get_color(&r2d_start_get_color,&r2d_sca_up1);
            r2d_patch_get_color(&r2d_start_get_color,&r2d_sca_up2);
		}
        else
		{
			
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sdb_down1);
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sdb_down2);
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sda_up1);
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sda_up2);

            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_scb_down1);
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_scb_down2);
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sca_up1);
            r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sca_up2);
		}
	}
	else
	{
		if (use_foreground_color)
			{
		       if ((r2d_g_old_foreground_pixelvalue != ((T_R2D_GC*)dst_gc)->foreground_pixel_value)
			      || 
		          (r2d_g_old_background_pixelvalue != ((T_R2D_GC*)dst_gc)->background_pixel_value))
			   {
                    r2d_patch_color_conversion(dst_gc);
					r2d_g_old_foreground_pixelvalue=((T_R2D_GC*)dst_gc)->foreground_pixel_value;
                    r2d_g_old_background_pixelvalue=((T_R2D_GC*)dst_gc)->background_pixel_value;
			   }
		
			}
	}

	if (r2d_g_old_srcdst != srcdst)
	{
		r2d_g_old_srcdst=srcdst;

	    // Path color conversion
        if (srcdst==R2D_LCDLCD)
		{
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcolb_down1);
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcolb_down2);
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcola_up1);
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcola_up2);

		   // write_shift_pixel_down
		   r2d_patch_branch(&r2d_skip_load_src_a_up1,&r2d_no_null_src_counter_a,FALSE);//src
		   r2d_patch_branch(&r2d_skip_load_src_a_up2,&r2d_end_a_up2,FALSE);//src

		   // write_shift_pixel_up
		   r2d_patch_branch(&r2d_skip_load_src_b_down1,&r2d_no_null_src_counter_b,FALSE);//src
		   r2d_patch_branch(&r2d_skip_load_src_b_down2,&r2d_end_b_down2,FALSE);//src

		   

		   r2d_patch_branch(&r2d_skip_shift_down_downa,&r2d_end_downa,FALSE);// dst
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downb,FALSE);//src
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downc,FALSE);//dst

		   r2d_patch_branch(&r2d_skip_shift_up_upa,&r2d_end_upa,FALSE);//dst
		   r2d_patch_branch(&r2d_skip_shift_up_upb,&r2d_end_upb,FALSE);//src
		   r2d_patch_branch(&r2d_skip_shift_up_upc,&r2d_end_upc,FALSE);//dst

		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_b_down1);
		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_b_down2);
		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_a_up1);
		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_a_up2);


		}

		if (srcdst==R2D_COLORCOLOR)
		{
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcolb_down1);
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcolb_down2);
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcola_up1);
           r2d_patch_code_block(&r2d_lcd_start_nothing,&r2d_sconvcola_up2);

		   // write_shift_pixel_down
		   r2d_patch_branch(&r2d_skip_load_src_a_up1,&r2d_no_null_src_counter_a,TRUE);//src
		   r2d_patch_branch(&r2d_skip_load_src_a_up2,&r2d_end_a_up2,TRUE);//src

		   // write_shift_pixel_up
		   r2d_patch_branch(&r2d_skip_load_src_b_down1,&r2d_no_null_src_counter_b,TRUE);//src
		   r2d_patch_branch(&r2d_skip_load_src_b_down2,&r2d_end_b_down2,TRUE);//src

		   

		   r2d_patch_branch(&r2d_skip_shift_down_downa,&r2d_end_downa,TRUE);// dst
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downb,TRUE);//src
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downc,TRUE);//dst

		   r2d_patch_branch(&r2d_skip_shift_up_upa,&r2d_end_upa,TRUE);//dst
		   r2d_patch_branch(&r2d_skip_shift_up_upb,&r2d_end_upb,TRUE);//src
		   r2d_patch_branch(&r2d_skip_shift_up_upc,&r2d_end_upc,TRUE);//dst

		   r2d_patch_inst(&r2d_always_read_down,&r2d_always_read_b_down1);
		   r2d_patch_inst(&r2d_always_read_down,&r2d_always_read_b_down2);
		   r2d_patch_inst(&r2d_always_read_up,&r2d_always_read_a_up1);
		   r2d_patch_inst(&r2d_always_read_up,&r2d_always_read_a_up2);
		}

        if ((srcdst==R2D_COLORLCD))
		{
           r2d_patch_code_block(&r2d_start_color_to_lcd,&r2d_sconvcolb_down1);
           r2d_patch_code_block(&r2d_start_color_to_lcd,&r2d_sconvcolb_down2);
           r2d_patch_code_block(&r2d_start_color_to_lcd,&r2d_sconvcola_up1);
           r2d_patch_code_block(&r2d_start_color_to_lcd,&r2d_sconvcola_up2);

		   // write_shift_pixel_down
		   r2d_patch_branch(&r2d_skip_load_src_a_up1,&r2d_no_null_src_counter_a,TRUE);//src
		   r2d_patch_branch(&r2d_skip_load_src_a_up2,&r2d_end_a_up2,TRUE);//src

		   // write_shift_pixel_up
		   r2d_patch_branch(&r2d_skip_load_src_b_down1,&r2d_no_null_src_counter_b,TRUE);//src
		   r2d_patch_branch(&r2d_skip_load_src_b_down2,&r2d_end_b_down2,TRUE);//src

		   

		   r2d_patch_branch(&r2d_skip_shift_down_downa,&r2d_end_downa,FALSE);// dst
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downb,TRUE);//src
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downc,FALSE);//dst

		   r2d_patch_branch(&r2d_skip_shift_up_upa,&r2d_end_upa,FALSE);//dst
		   r2d_patch_branch(&r2d_skip_shift_up_upb,&r2d_end_upb,TRUE);//src
		   r2d_patch_branch(&r2d_skip_shift_up_upc,&r2d_end_upc,FALSE);//dst

		   r2d_patch_inst(&r2d_always_read_down,&r2d_always_read_b_down1);
		   r2d_patch_inst(&r2d_always_read_down,&r2d_always_read_b_down2);
		   r2d_patch_inst(&r2d_always_read_up,&r2d_always_read_a_up1);
		   r2d_patch_inst(&r2d_always_read_up,&r2d_always_read_a_up2);
		}

		

        if ((srcdst==R2D_LCDCOLOR))
		{
           r2d_patch_code_block(&r2d_start_lcd_to_color,&r2d_sconvcolb_down1);
           r2d_patch_code_block(&r2d_start_lcd_to_color,&r2d_sconvcolb_down2);
           r2d_patch_code_block(&r2d_start_lcd_to_color,&r2d_sconvcola_up1);
           r2d_patch_code_block(&r2d_start_lcd_to_color,&r2d_sconvcola_up2);

		   // write_shift_pixel_down
		   r2d_patch_branch(&r2d_skip_load_src_a_up1,&r2d_no_null_src_counter_a,FALSE);//src
		   r2d_patch_branch(&r2d_skip_load_src_a_up2,&r2d_end_a_up2,FALSE);//src

		   // write_shift_pixel_up
		   r2d_patch_branch(&r2d_skip_load_src_b_down1,&r2d_no_null_src_counter_b,FALSE);//src
		   r2d_patch_branch(&r2d_skip_load_src_b_down2,&r2d_end_b_down2,FALSE);//src

		   

		   r2d_patch_branch(&r2d_skip_shift_down_downa,&r2d_end_downa,TRUE);// dst
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downb,FALSE);//src
		   r2d_patch_branch(&r2d_skip_shift_down_downb,&r2d_end_downc,TRUE);//dst

		   r2d_patch_branch(&r2d_skip_shift_up_upa,&r2d_end_upa,TRUE);//dst
		   r2d_patch_branch(&r2d_skip_shift_up_upb,&r2d_end_upb,FALSE);//src
		   r2d_patch_branch(&r2d_skip_shift_up_upc,&r2d_end_upc,TRUE);//dst

		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_b_down1);
		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_b_down2);
		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_a_up1);
		   r2d_patch_inst(&r2d_never_write,&r2d_always_read_a_up2);
		}

	// Patch writing subroutines
    // Remove part of code not required when dst is R2D color
    // framebuffer (some branch are used to skip the parts)
    if ((srcdst==R2D_COLORCOLOR) || (srcdst==R2D_LCDCOLOR))
    {
       r2d_patch_inst(&r2d_always_write_down,&r2d_swb_down1);
       r2d_patch_inst(&r2d_always_write_down,&r2d_swb_down2);
       r2d_patch_inst(&r2d_always_write_up,&r2d_swa_up1);
       r2d_patch_inst(&r2d_always_write_up,&r2d_swa_up2);

       r2d_patch_branch(&r2d_skip_color_proc_a,&r2d_end_ynb_color_dst_a,TRUE);
       r2d_patch_branch(&r2d_skip_color_proc_b,&r2d_end_ynb_color_dst_b,TRUE);
       r2d_patch_branch(&r2d_skip_color_dst_a,&r2d_enda,TRUE);
       r2d_patch_branch(&r2d_skip_color_dst_b,&r2d_endb,TRUE);
    }
    else
    {
       r2d_patch_inst(&r2d_never_write,&r2d_swb_down1);
       r2d_patch_inst(&r2d_never_write,&r2d_swb_down2);
       r2d_patch_inst(&r2d_never_write,&r2d_swa_up1);
       r2d_patch_inst(&r2d_never_write,&r2d_swa_up2);

       r2d_patch_branch(&r2d_skip_color_proc_a,&r2d_end_ynb_color_dst_a,FALSE);
       r2d_patch_branch(&r2d_skip_color_proc_b,&r2d_end_ynb_color_dst_b,FALSE);
       r2d_patch_branch(&r2d_skip_color_dst_a,&r2d_enda,FALSE);
       r2d_patch_branch(&r2d_skip_color_dst_b,&r2d_endb,FALSE);
    }


    // Update or restore shifts related to src
    if ((srcdst==R2D_COLORCOLOR) || (srcdst==R2D_COLORLCD))
    {
        // Patch list for write_shift_pixel_down
        r2d_patch_shift(&r2d_sft_src_c_b_down1,0,1);
        r2d_patch_shift(&r2d_sft_src_c_b_down2,0,1);

        r2d_patch_shift(&r2d_sft_b_c_b_down1,0,0);
        r2d_patch_shift(&r2d_sft_b_c_b_down2,0,0);

        r2d_patch_shift(&r2d_sft_srcb__b_down1,0,0); // Read already done
        r2d_patch_shift(&r2d_sft_srcb__b_down2,0,0); // No need to make free area

        // Patch list for write_shift_pixel_up
        r2d_patch_shift(&r2d_sft_src_c_a_up1,0,0);
        r2d_patch_shift(&r2d_sft_src_c_a_up2,0,0);

        r2d_patch_shift(&r2d_sft_b_c_a_up1,0,0);
        r2d_patch_shift(&r2d_sft_b_c_a_up2,0,0);

        r2d_patch_shift(&r2d_sft_srcb__a_up1,0,1); // Read already done
        r2d_patch_shift(&r2d_sft_srcb__a_up2,0,1); // No need to make free area

        // Patch list for shift_pixel_down
       r2d_patch_shift(&r2d_sft_src_c_downb,0,1);
       r2d_patch_moveshift(&r2d_sft_srcb_n_downb,32,0);

        // Patch list for shift_pixel_up
       r2d_patch_shift(&r2d_sft_src_c_upb,0,0);
       r2d_patch_moveshift(&r2d_sft_srcb_n_upb,32,1);

    }
    else
    {
       // Patch list for write_shift_pixel_down
        r2d_patch_shift(&r2d_sft_src_c_b_down1,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,1);
        r2d_patch_shift(&r2d_sft_src_c_b_down2,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,1);

        r2d_patch_shift(&r2d_sft_b_c_b_down1,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);
        r2d_patch_shift(&r2d_sft_b_c_b_down2,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);

        r2d_patch_shift(&r2d_sft_srcb__b_down1,R2D_PIXEL_DEPTH,0);
        r2d_patch_shift(&r2d_sft_srcb__b_down2,R2D_PIXEL_DEPTH,0);

        // Patch list for write_shift_pixel_up
        r2d_patch_shift(&r2d_sft_src_c_a_up1,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);
        r2d_patch_shift(&r2d_sft_src_c_a_up2,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);

        r2d_patch_shift(&r2d_sft_b_c_a_up1,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);
        r2d_patch_shift(&r2d_sft_b_c_a_up2,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);

        r2d_patch_shift(&r2d_sft_srcb__a_up1,R2D_PIXEL_DEPTH,1);
        r2d_patch_shift(&r2d_sft_srcb__a_up2,R2D_PIXEL_DEPTH,1);

        // Patch list for shift_pixel_down
       r2d_patch_shift(&r2d_sft_src_c_downb,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,1);
       r2d_patch_moveshift(&r2d_sft_srcb_n_downb,R2D_PIXEL_DEPTH,0);

        // Patch list for shift_pixel_up
       r2d_patch_shift(&r2d_sft_src_c_upb,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);
       r2d_patch_moveshift(&r2d_sft_srcb_n_upb,R2D_PIXEL_DEPTH,1);
    }



    // Update (or restore) shifts related to dst
    if ((srcdst==R2D_COLORCOLOR) || (srcdst==R2D_LCDCOLOR))
    {
       // Patch list for write_shift_pixel_down
       r2d_patch_moveshift(&r2d_sft_dst_n_b_down1,32,0); // Shift when dst is R2D color
                                        // framebuffer.
                                        // Only instructions using dst
                                        // are impacted
       r2d_patch_moveshift(&r2d_sft_dst_n_b_down2,32,0);

       r2d_patch_shift(&r2d_sft_dstc__b_down1,0,0); // Already read
       r2d_patch_shift(&r2d_sft_dstc__b_down2,0,0); // No need to make free area

       r2d_patch_shift(&r2d_sft_dstb_c_b_down1,0,1);
       r2d_patch_shift(&r2d_sft_dstb_c_b_down2,0,1);
       r2d_patch_shift(&r2d_sft_d_c_b_down1,0,0);
       r2d_patch_shift(&r2d_sft_d_c_b_down2,0,0);
       r2d_patch_shift(&r2d_sft_dstc_c_b_down1,0,1);
       r2d_patch_shift(&r2d_sft_dstc_c_b_down2,0,1);



       // Patch list for write_shift_pixel_up
       r2d_patch_moveshift(&r2d_sft_dst_n_a_up1,32,1);
       r2d_patch_moveshift(&r2d_sft_dst_n_a_up2,32,1);

       r2d_patch_shift(&r2d_sft_dstc__a_up1,0,1); // Already read
       r2d_patch_shift(&r2d_sft_dstc__a_up2,0,1); // No need to make free area

       r2d_patch_shift(&r2d_sft_b_c_a_up1,0,0);
       r2d_patch_shift(&r2d_sft_b_c_a_up2,0,0);
       


       // Patch list for shift_pixel_down
       r2d_patch_moveshift(&r2d_sft_dst_n_downa,32,0);
       r2d_patch_moveshift(&r2d_sft_dst_n_downb,32,0);
       r2d_patch_moveshift(&r2d_sft_dst_n_downc,32,0);

       r2d_patch_shift(&r2d_sft_src_c_downa,0,1);
       r2d_patch_moveshift(&r2d_sft_srcb_n_downa,32,0);
       r2d_patch_shift(&r2d_sft_src_c_downc,0,1);
       r2d_patch_moveshift(&r2d_sft_srcb_n_downc,32,0);


       // Patch list for shift_pixel_up
       r2d_patch_moveshift(&r2d_sft_dst_n_upa,32,1);
       r2d_patch_moveshift(&r2d_sft_dst_n_upb,32,1);
       r2d_patch_moveshift(&r2d_sft_dst_n_upc,32,1);

       r2d_patch_shift(&r2d_sft_src_c_upa,0,0);
       r2d_patch_moveshift(&r2d_sft_srcb_n_upa,32,1);
       r2d_patch_shift(&r2d_sft_src_c_upc,0,0);
       r2d_patch_moveshift(&r2d_sft_srcb_n_upc,32,1);


    }
    else
    {
       
      
       // Patch list for write_shift_pixel_down
       r2d_patch_moveshift(&r2d_sft_dst_n_b_down1,R2D_PIXEL_DEPTH,0); // Shift when dst is R2D color
                                                     // framebuffer.
                                                     // Only instructions using dst
                                                     // are impacted
       r2d_patch_moveshift(&r2d_sft_dst_n_b_down2,R2D_PIXEL_DEPTH,0);

       r2d_patch_shift(&r2d_sft_dstc__b_down1,R2D_PIXEL_DEPTH,0);
       r2d_patch_shift(&r2d_sft_dstc__b_down2,R2D_PIXEL_DEPTH,0);

       r2d_patch_shift(&r2d_sft_dstb_c_b_down1,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),1);
       r2d_patch_shift(&r2d_sft_dstb_c_b_down2,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),1);
       r2d_patch_shift(&r2d_sft_d_c_b_down1,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),0);
       r2d_patch_shift(&r2d_sft_d_c_b_down2,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),0);
       r2d_patch_shift(&r2d_sft_dstc_c_b_down1,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),1);
       r2d_patch_shift(&r2d_sft_dstc_c_b_down2,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),1);

       // Patch list for write_shift_pixel_up
       r2d_patch_moveshift(&r2d_sft_dst_n_a_up1,R2D_PIXEL_DEPTH,1);
       r2d_patch_moveshift(&r2d_sft_dst_n_a_up2,R2D_PIXEL_DEPTH,1);

       r2d_patch_shift(&r2d_sft_dstc__a_up1,R2D_PIXEL_DEPTH,1);
       r2d_patch_shift(&r2d_sft_dstc__a_up2,R2D_PIXEL_DEPTH,1);

       r2d_patch_shift(&r2d_sft_b_c_a_up1,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),0);
       r2d_patch_shift(&r2d_sft_b_c_a_up2,((1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH),0);
       

       // Patch list for shift_pixel_down
       r2d_patch_moveshift(&r2d_sft_dst_n_downa,R2D_PIXEL_DEPTH,0);
       r2d_patch_moveshift(&r2d_sft_dst_n_downb,R2D_PIXEL_DEPTH,0);
       r2d_patch_moveshift(&r2d_sft_dst_n_downc,R2D_PIXEL_DEPTH,0);

       r2d_patch_shift(&r2d_sft_src_c_downa,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,1);
       r2d_patch_moveshift(&r2d_sft_srcb_n_downa,R2D_PIXEL_DEPTH,0);
       r2d_patch_shift(&r2d_sft_src_c_downc,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,1);
       r2d_patch_moveshift(&r2d_sft_srcb_n_downc,R2D_PIXEL_DEPTH,0);


       // Patch list for shift_pixel_up
       r2d_patch_moveshift(&r2d_sft_dst_n_upa,R2D_PIXEL_DEPTH,1);
       r2d_patch_moveshift(&r2d_sft_dst_n_upb,R2D_PIXEL_DEPTH,1);
       r2d_patch_moveshift(&r2d_sft_dst_n_upc,R2D_PIXEL_DEPTH,1);

       r2d_patch_shift(&r2d_sft_src_c_upa,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);
       r2d_patch_moveshift(&r2d_sft_srcb_n_upa,R2D_PIXEL_DEPTH,1);
       r2d_patch_shift(&r2d_sft_src_c_upc,(1<<R2D_MEMORY_WORD) - R2D_PIXEL_DEPTH,0);
       r2d_patch_moveshift(&r2d_sft_srcb_n_upc,R2D_PIXEL_DEPTH,1);

    }
	
   }
}


#endif