仮想VRAMにおける、x,y座標系のテーブル位置変換の考察(なんちゃつて)(x240)

x カラー液晶は、 ST7789 ST7789V2 ATM0130B3 の事
x (レポート風(なんちゃつて))

x 実験結果は、一番したです。コメントも見てください。

本件の目的
小型マイコンにおける座標変換の高速化
1. 一次にてテーブルでyに対して掛け算を使用した場合の速度
2. 一次にてテーブルで表引きを使用した場合の速度
3. 二次テーブルを使用した場合の速度

注意、高速で十分なワイヤーロジックのハードを搭載した
ESP32、STM32F7では、差が出ないと予想される。
よつて、本件の対象外
掛け算を使用

条件は、約180万回、ループしてusを測定
カラーは、0とする。
ループは、240が二回
あまり差がでないので30回実施
ハードは、M0系のSTM32G071(32MHz)で実施する


```c++


測定開始

for(int s=0;s<30;s++){

  for(int y=0;y<240;y++){
    for(int x=0;x<240;x++){
      処理
    }
  }

}

測定終了


```




例1


```c++

    //ドットのカラーの設定
    buffer[ y*240 + x ] = color;


```

例2


```c++


    //ドットのカラーの設定
    buffer[ y_shift[y] + x ] = color;


```

例3


```c++

    //ドットのカラーの設定
    buffer[y][x] = color;


```



●思考実験　エコな実験で電気も計算機も不要。


Z80Aまたは、8086ぽい、疑似アセンブラ

LD ロード命令
ADD 加算命令
SUB 引き算命令
SFT シフト命令　1個右シフト


例1

AXは、y
BXは、x
CXは、yのコピー
DXは、xのコピー
EXは、カラー
HXは、テーブルのインデックス メイン
IXは、テーブルのインデックス サブ


予想では、掛け算の速さによっては、速度は。ほぼ、かわらないと
思われる。

アセンブラは、たぶん、いろいろ間違っている　あくまでイメージ

```

例1

[HX+(y*240)+x]=EX

LD BX,AX

SFT BX   //BX=BX<<1
SFT BX   //BX=BX<<1
SFT BX   //BX=BX<<1
SFT BX   //BX=BX<<1

LD  AX,DX

SFT BX
ADD AX,BX //BX=BX<<1

SFT BX
ADD AX,BX //BX=BX<<1

SFT BX
ADD AX,BX //BX=BX<<1

SFT BX
ADD AX,BX //BX=BX<<1

ADD AX,HX
LD  HX,AX
LD  AX,EX
LD  [HX],AX

例2

[HX+[IX+y]+x]=EX

LD  AX,IX     //AX=IX
ADD AX,CX     //AX=AX+CX
LD  IX,AX     //IX=AX
LD  AX,[IX]   //AX=[IX]
ADD AX,DX     //AX=AX+DX
ADD AX,HX     //AX=AX+HX
LD  HX,AX     //HX=AX
LD  AX,EX     //AX=EX
LD  [HX],AX   //[HX]=AX


例3

[[HX+y]+x]=EX

LD  HX,AX     //HX=AX
ADD AX,CX     //AX=AX+CX
LD  HX,AX     //HX=AX
LD  AX,[HX]   //AX=[HX]   
LD  AX,BX     //AX=AX+BX
LD  HX,AX     //HX=AX
LD  AX,EX     //AX=EX
LD  [HX],AX   //[HX]=AX


```

●結果

誤差の範囲でどちらでもよい。
どこかのタイミングで互換の為に
掛け算による座標変換に戻しておく。
STM32の掛け算装置は、大変に優秀です。
注意、SRAMの関係上、60ラインです。

まちがい

![o_cop734.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/bf1c29d5-c882-47f1-be2e-f5c1c74a137c.jpeg)

まちがい

![o_cop735.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/32e65e92-457c-959a-6a29-94679b5fba94.jpeg)

まちがい

![o_cop736.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/30c789d2-da9c-5305-8c53-3bf8608ae749.jpeg)

指摘があり調査しました。
まちがい　正しくは、さらに下のプログラム
ループの初期化が抜けている

```c++:main.cpp


//H_xy_convert_071_1

int y_shift[] = {
  0, 240, 480, 720, 960, 1200, 1440, 1680, 1920, 2160,
  2400, 2640, 2880, 3120, 3360, 3600, 3840, 4080, 4320, 4560,
  4800, 5040, 5280, 5520, 5760, 6000, 6240, 6480, 6720, 6960,
  7200, 7440, 7680, 7920, 8160, 8400, 8640, 8880, 9120, 9360,
  9600, 9840, 10080, 10320, 10560, 10800, 11040, 11280, 11520, 11760,
  12000, 12240, 12480, 12720, 12960, 13200, 13440, 13680, 13920, 14160,
  14400, 14640, 14880, 15120, 15360, 15600, 15840, 16080, 16320, 16560,
  16800, 17040, 17280, 17520, 17760, 18000, 18240, 18480, 18720, 18960,
  19200, 19440, 19680, 19920, 20160, 20400, 20640, 20880, 21120, 21360,
  21600, 21840, 22080, 22320, 22560, 22800, 23040, 23280, 23520, 23760,
  24000, 24240, 24480, 24720, 24960, 25200, 25440, 25680, 25920, 26160,
  26400, 26640, 26880, 27120, 27360, 27600, 27840, 28080, 28320, 28560,
  28800, 29040, 29280, 29520, 29760, 30000, 30240, 30480, 30720, 30960,
  31200, 31440, 31680, 31920, 32160, 32400, 32640, 32880, 33120, 33360,
  33600, 33840, 34080, 34320, 34560, 34800, 35040, 35280, 35520, 35760,
  36000, 36240, 36480, 36720, 36960, 37200, 37440, 37680, 37920, 38160,
  38400, 38640, 38880, 39120, 39360, 39600, 39840, 40080, 40320, 40560,
  40800, 41040, 41280, 41520, 41760, 42000, 42240, 42480, 42720, 42960,
  43200, 43440, 43680, 43920, 44160, 44400, 44640, 44880, 45120, 45360,
  45600, 45840, 46080, 46320, 46560, 46800, 47040, 47280, 47520, 47760,
  48000, 48240, 48480, 48720, 48960, 49200, 49440, 49680, 49920, 50160,
  50400, 50640, 50880, 51120, 51360, 51600, 51840, 52080, 52320, 52560,
  52800, 53040, 53280, 53520, 53760, 54000, 54240, 54480, 54720, 54960,
  55200, 55440, 55680, 55920, 56160, 56400, 56640, 56880, 57120, 57360
};


#define ex1 (1)
//#define ex2 (1)
//#define ex3 (1)

#if defined(ex1)
word buffer[240 * 60];
#endif
#if defined(ex2)
word buffer[240 * 60];
#endif
#if defined(ex3)
word buffer[240][60];
#endif

void setup() {

  Serial.begin( 9600 );     // シリアル通信を初期化する。通信速度は9600bps

  Serial.println();      //改行
  Serial.print("START"); //STARTと表示
  Serial.println();      //改行

}//setup


void loop() {

  int st = 0; //測定開始時間
  int en = 0; //測定終了時間
  int ti = 0; //測定経過時間
  word color = 0; //カラーコード

  st = micros(); //測定開始

  for (int s; s < 30; s++) {
    for (int y; y < 60; y++) {
      for (int x; x < 240; x++) {

#if defined(ex1)
        //ドットのカラーの設定
        buffer[ y * 240 + x ] = color;
#endif
#if defined(ex2)
        //ドットのカラーの設定
        buffer[ y_shift[y] + x ] = color;
#endif
#if defined(ex3)
        //ドットのカラーの設定
        buffer[y][x] = color;
#endif

      }//x
    }//y
  }//30count

  en = micros(); //測定開始
  
  ti = en - st;


#if defined(ex1)
Serial.print("buffer[ y * 240 + x ]: ");  //処理1
#endif
#if defined(ex2)
Serial.print("buffer[ y_shift[y] + x ]: ");  //処理2
#endif
#if defined(ex3)
Serial.print("buffer[y][x]: ");  //処理3
#endif


  Serial.print(ti);    //測定経過時間
  Serial.print("us");  //単位
  Serial.println();    //改行

  delay(1000); //1秒待つ

} //loop

```

結果は、予想通り

●結果

誤差の範囲でどちらでもよい。
どこかのタイミングで互換の為に
掛け算による座標変換に戻しておく。
STM32の掛け算装置は、大変に優秀です。
注意、SRAMの関係上、30ラインです。

まちがい

![o_cop740.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/9ad11ca6-4c6c-066b-c3be-bd9b0231bd5f.jpeg)

まちがい

![o_cop741.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/14a83e63-0e4d-0f3e-9078-b1e6dc4b2ae1.jpeg)

まちがい

![o_cop742.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/29cae269-b2e4-7e77-7536-6900eb8e9913.jpeg)

指摘のあった通り
配列の設定をまちがえました。
正しいプログラムは、さらに下です。


```c++



//H_xy_convert_071_1

int y_shift[] = {
  0, 240, 480, 720, 960, 1200, 1440, 1680, 1920, 2160,
  2400, 2640, 2880, 3120, 3360, 3600, 3840, 4080, 4320, 4560,
  4800, 5040, 5280, 5520, 5760, 6000, 6240, 6480, 6720, 6960,
  7200, 7440, 7680, 7920, 8160, 8400, 8640, 8880, 9120, 9360,
  9600, 9840, 10080, 10320, 10560, 10800, 11040, 11280, 11520, 11760,
  12000, 12240, 12480, 12720, 12960, 13200, 13440, 13680, 13920, 14160,
  14400, 14640, 14880, 15120, 15360, 15600, 15840, 16080, 16320, 16560,
  16800, 17040, 17280, 17520, 17760, 18000, 18240, 18480, 18720, 18960,
  19200, 19440, 19680, 19920, 20160, 20400, 20640, 20880, 21120, 21360,
  21600, 21840, 22080, 22320, 22560, 22800, 23040, 23280, 23520, 23760,
  24000, 24240, 24480, 24720, 24960, 25200, 25440, 25680, 25920, 26160,
  26400, 26640, 26880, 27120, 27360, 27600, 27840, 28080, 28320, 28560,
  28800, 29040, 29280, 29520, 29760, 30000, 30240, 30480, 30720, 30960,
  31200, 31440, 31680, 31920, 32160, 32400, 32640, 32880, 33120, 33360,
  33600, 33840, 34080, 34320, 34560, 34800, 35040, 35280, 35520, 35760,
  36000, 36240, 36480, 36720, 36960, 37200, 37440, 37680, 37920, 38160,
  38400, 38640, 38880, 39120, 39360, 39600, 39840, 40080, 40320, 40560,
  40800, 41040, 41280, 41520, 41760, 42000, 42240, 42480, 42720, 42960,
  43200, 43440, 43680, 43920, 44160, 44400, 44640, 44880, 45120, 45360,
  45600, 45840, 46080, 46320, 46560, 46800, 47040, 47280, 47520, 47760,
  48000, 48240, 48480, 48720, 48960, 49200, 49440, 49680, 49920, 50160,
  50400, 50640, 50880, 51120, 51360, 51600, 51840, 52080, 52320, 52560,
  52800, 53040, 53280, 53520, 53760, 54000, 54240, 54480, 54720, 54960,
  55200, 55440, 55680, 55920, 56160, 56400, 56640, 56880, 57120, 57360
};


#define ex1 (1)
//#define ex2 (1)
//#define ex3 (1)

#if defined(ex1)
word buffer[240 * 30];
#endif
#if defined(ex2)
word buffer[240 * 30];
#endif
#if defined(ex3)
word buffer[240][30];
#endif

void setup() {

  Serial.begin( 9600 );     // シリアル通信を初期化する。通信速度は9600bps

  Serial.println();      //改行
  Serial.print("START"); //STARTと表示
  Serial.println();      //改行

}//setup


void loop() {

  int st = 0; //測定開始時間
  int en = 0; //測定終了時間
  int ti = 0; //測定経過時間
  word color = 0; //カラーコード

  st = micros(); //測定開始

  for (int s=0; s < 30; s++) {
    for (int y=0; y < 30; y++) {
      for (int x=0; x < 240; x++) {

#if defined(ex1)
        //ドットのカラーの設定
        buffer[ y * 240 + x ] = color;
#endif
#if defined(ex2)
        //ドットのカラーの設定
        buffer[ y_shift[y] + x ] = color;
#endif
#if defined(ex3)
        //ドットのカラーの設定
        buffer[y][x] = color;
#endif

      }//x
    }//y
  }//30count

  en = micros(); //測定開始
  
  ti = en - st;


#if defined(ex1)
Serial.print("buffer[ y * 240 + x ]: ");  //処理1
#endif
#if defined(ex2)
Serial.print("buffer[ y_shift[y] + x ]: ");  //処理2
#endif
#if defined(ex3)
Serial.print("buffer[y][x]: ");  //処理3
#endif


  Serial.print(ti);    //測定経過時間
  Serial.print("us");  //単位
  Serial.println();    //改行

  delay(1000); //1秒待つ

} //loop


```

------------------------------------------------------

●結果●　再修正3回目　コメントを見てください。

![o_cop747.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/126bbab6-b359-5c74-3059-4965ef782100.jpeg)


=記事の読者むけの簡単な説明=
仮想VRAM方式の最大の特徴は、一瞬で画面が切り替わった様に見える。
大量に描画する時に高速。
なんとなく、わかりずらいのは、仮想VRAMの構造とアクセス速度の
話があるため。


誤差の範囲でどちらでもよい。
どこかのタイミングで互換の為に
掛け算による座標変換に戻しておく。
STM32の掛け算装置は、大変に優秀です。
注意、SRAMの関係上、30ラインです。

![o_cop748.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/42e84e78-d944-4df0-e1ce-8a378e7d1ca9.jpeg)

![o_cop749.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ac6b5822-b06f-5884-1ad9-e991ffdfdf51.jpeg)

![o_cop750.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/c402624d-5377-ec0c-4efa-bf00a0ef3ac0.jpeg)


```c++



//H_xy_convert_071_1

int y_shift[] = {
  0, 240, 480, 720, 960, 1200, 1440, 1680, 1920, 2160,
  2400, 2640, 2880, 3120, 3360, 3600, 3840, 4080, 4320, 4560,
  4800, 5040, 5280, 5520, 5760, 6000, 6240, 6480, 6720, 6960,
  7200, 7440, 7680, 7920, 8160, 8400, 8640, 8880, 9120, 9360,
  9600, 9840, 10080, 10320, 10560, 10800, 11040, 11280, 11520, 11760,
  12000, 12240, 12480, 12720, 12960, 13200, 13440, 13680, 13920, 14160,
  14400, 14640, 14880, 15120, 15360, 15600, 15840, 16080, 16320, 16560,
  16800, 17040, 17280, 17520, 17760, 18000, 18240, 18480, 18720, 18960,
  19200, 19440, 19680, 19920, 20160, 20400, 20640, 20880, 21120, 21360,
  21600, 21840, 22080, 22320, 22560, 22800, 23040, 23280, 23520, 23760,
  24000, 24240, 24480, 24720, 24960, 25200, 25440, 25680, 25920, 26160,
  26400, 26640, 26880, 27120, 27360, 27600, 27840, 28080, 28320, 28560,
  28800, 29040, 29280, 29520, 29760, 30000, 30240, 30480, 30720, 30960,
  31200, 31440, 31680, 31920, 32160, 32400, 32640, 32880, 33120, 33360,
  33600, 33840, 34080, 34320, 34560, 34800, 35040, 35280, 35520, 35760,
  36000, 36240, 36480, 36720, 36960, 37200, 37440, 37680, 37920, 38160,
  38400, 38640, 38880, 39120, 39360, 39600, 39840, 40080, 40320, 40560,
  40800, 41040, 41280, 41520, 41760, 42000, 42240, 42480, 42720, 42960,
  43200, 43440, 43680, 43920, 44160, 44400, 44640, 44880, 45120, 45360,
  45600, 45840, 46080, 46320, 46560, 46800, 47040, 47280, 47520, 47760,
  48000, 48240, 48480, 48720, 48960, 49200, 49440, 49680, 49920, 50160,
  50400, 50640, 50880, 51120, 51360, 51600, 51840, 52080, 52320, 52560,
  52800, 53040, 53280, 53520, 53760, 54000, 54240, 54480, 54720, 54960,
  55200, 55440, 55680, 55920, 56160, 56400, 56640, 56880, 57120, 57360
};


//#define ex1 (1)
//#define ex2 (1)
#define ex3 (1)

#if defined(ex1)
//           y     x
word buffer[30 * 240];
#endif
#if defined(ex2)
//           y     x
word buffer[30 * 240];
#endif
#if defined(ex3)
//            y    x
word buffer[ 30][240];
#endif

void setup() {

  Serial.begin( 9600 );     // シリアル通信を初期化する。通信速度は9600bps

  Serial.println();      //改行
  Serial.print("START"); //STARTと表示
  Serial.println();      //改行

}//setup


void loop() {

  int st = 0; //測定開始時間
  int en = 0; //測定終了時間
  int ti = 0; //測定経過時間
  //word color = 0; //カラーコード
  word color = 0x1234; //カラーコード

  st = micros(); //測定開始

  for (int s=0; s < 30; s++) {
    for (int y=0; y < 30; y++) {
      for (int x=0; x < 240; x++) {

#if defined(ex1)
        //ドットのカラーの設定
        buffer[ y * 240 + x ] = color;
#endif
#if defined(ex2)
        //ドットのカラーの設定
        buffer[ y_shift[y] + x ] = color;
#endif
#if defined(ex3)
        //ドットのカラーの設定
        buffer[y][x] = color;
#endif

      }//x
    }//y
  }//30count

  en = micros(); //測定開始
  
  ti = en - st;


#if defined(ex1)
Serial.print("buffer[ y * 240 + x ]: ");  //処理1
#endif
#if defined(ex2)
Serial.print("buffer[ y_shift[y] + x ]: ");  //処理2
#endif
#if defined(ex3)
Serial.print("buffer[y][x]: ");  //処理3
#endif


  Serial.print(ti);    //測定経過時間
  Serial.print("us");  //単位
  Serial.println();    //改行

  delay(1000); //1秒待つ

} //loop


```