ZX81の回想禄

PR

×

プロフィール

ZX81

ZX81

カレンダー

コメント新着

コメントに書き込みはありません。

キーワードサーチ

▼キーワード検索

2026.04.06
XML
​​1行ずらしてコピーする事(行コピー方式)で高速化しましたが
さらなる方法としてリングバッファでの描画の実装を試みます。

1行上にスクロールする場合を図解してみました。



 0~22行を1~23行にコピー後に0行目のみを再描画する事で、
 全行描画よりも高速化が可能となりました。

 しかし、23行分をコピーする事はZX81にとっては痛いタイムロスとなります。



 次に、今回紹介する描画開始位置をずらしていく方式です。
 描画開始位置であるstart_yを+1とし、元々start_yの行のみを再描画するものです。

 デメリットはソースが少し複雑化する事です。


以下、ソースコードとなります。

ーーーーーmap.cpp
/*
 *      ZX81 Map Handling Module program
 */
#include <stdio.h>
#include <string.h>
#include "map.h"
unsigned char rock_tbl[19][3] = {
// screen
{0x80,0x00,0x00},{0x40,0x00,0x00},{0x20,0x00,0x00},{0x10,0x00,0x00},{0x08,0x00,0x00},
{0x04,0x00,0x00},{0x02,0x00,0x00},{0x01,0x00,0x00},{0x00,0x80,0x00},{0x00,0x40,0x00},
{0x00,0x20,0x00},{0x00,0x10,0x00},
// scroll
{0x00,0x08,0x00},{0x00,0x04,0x00},{0x00,0x02,0x00},{0x00,0x01,0x00},{0x00,0x00,0x80},
{0x00,0x00,0x40},{0x00,0x00,0x20},
};
unsigned char rock_chr[4][2] =
{
{0x81, 0x05},{0x80, 0x01},
{0x03, 0x00},{0x87, 0x04}
};
int start_y = 0;
// Render buffers for smooth 2x2 tile scrolling (even/odd frames)
#define RENDER_DX22
#define RENDER_DY24
unsigned char render_buf_even[RENDER_DY][RENDER_DX];
unsigned char render_buf_odd[RENDER_DY][RENDER_DX];
int render_pos;
// screen address
#define D_FILE          0x400c
#define D_DX            33      // 32+1(CR)
#define D_DY            24
unsigned char* getscrnaddr(int posy, int posx)
{
#asm
    ld      ix,2
    add     ix,sp
;    push    de
    ld      d, (ix+2)       ; d=posy
    ld      e, (ix+0)       ; e=posx
    call    getscrnaddr
;    pop     de
    ret
getscrnaddr:
; IN:  D=posy, E=posx
; OUT: HL= screen address
;    push    bc
    ; HL = posy * 33
    ld      h, 0
    ld      l, d
    add     hl, hl          ; *2
    add     hl, hl          ; *4
    add     hl, hl          ; *8
    add     hl, hl          ; *16
    add     hl, hl          ; *32
    ld      b, 0
    ld      c, d
    add     hl, bc          ; +1 -> *33
    ; HL += posx
    ld      b, 0
    ld      c, e            ; c=posx
    add     hl, bc
    ; HL += D_FILE
    ld      bc,(D_FILE)
    inc     bc
    add     hl, bc
;    pop     bc
    ret
#endasm
}
void rock_render_line(int phys_y, int logical_row)
{
    int dx;
    unsigned char bit = 0x80;
    int rockx = 0;
    int rocky = (render_pos + logical_row * 2 + 1) / 4;
    int ptn   = (render_pos + logical_row * 2) & 0x03;   // 0 or 2
    if (render_pos & 0x01)
    {
        memset(&render_buf_odd[phys_y][1], 0, RENDER_DX - 2);
        for (dx = 1; dx <= RENDER_DX - 2; dx++)
        {
            if (rock_tbl[rocky][rockx] & bit)
                memcpy(&render_buf_odd[phys_y][dx], &rock_chr[ptn][0], 2);
            bit >>= 1;
            if (!bit) { bit = 0x80; rockx++; }
        }
    }
    else
    {
        memset(&render_buf_even[phys_y][1], 0, RENDER_DX - 2);
        for (dx = 1; dx <= RENDER_DX - 2; dx++)
        {
            if (rock_tbl[rocky][rockx] & bit)
                memcpy(&render_buf_even[phys_y][dx], &rock_chr[ptn][0], 2);
            bit >>= 1;
            if (!bit) { bit = 0x80; rockx++; }
        }
    }
}
// ----------------------------------------------------------
// 初期化
// ----------------------------------------------------------
void map_init(void)
{
    int logical_row;
    int phys_y;
    render_pos = 0;
    start_y    = 0;
    // -----------------------------
    // even バッファの初期化(render_pos=0)
    // -----------------------------
    for (logical_row = 0; logical_row < RENDER_DY; logical_row++)
    {
        render_buf_even[logical_row][0]             = 0x82;
        render_buf_even[logical_row][RENDER_DX-1]   = 0x81;
        phys_y = (start_y + logical_row) % RENDER_DY;
        rock_render_line(phys_y, logical_row);
    }
    // -----------------------------
    // odd バッファの初期化(render_pos-1 にして描く)
    // -----------------------------
    render_pos--;
    for (logical_row = 0; logical_row < RENDER_DY; logical_row++)
    {
        render_buf_odd[logical_row][0]              = 0x07;
        render_buf_odd[logical_row][RENDER_DX-1]    = 0x84;
        phys_y = (start_y + logical_row) % RENDER_DY;
        rock_render_line(phys_y, logical_row);
    }
    // 初期状態は render_pos++ に戻す
    render_pos++;
}
// ----------------------------------------------------------
// スクロール
//   dy < 0 : 上へ 1dot
//   dy > 0 : 下へ 1dot
//
// ルール:
//   render_pos++ の結果が奇数なら start_y++
//   render_pos-- の結果が偶数なら start_y--
// ----------------------------------------------------------
void map_scroll(int dy)
{
    int phys_y;
    int logical_row;
    if (dy < 0)
    {
        if (render_pos == 0) return;
        // 上へ 1dot
        render_pos--;
        // 結果が偶数なら start_y を -1
        if ((render_pos & 1) == 0)
            start_y = (start_y - 1 + RENDER_DY) % RENDER_DY;
        logical_row = 0;          // 画面の最上段が新規
        phys_y  = start_y;    // 論理 0 行目の物理行
        rock_render_line(phys_y, logical_row);
    }
    else if (dy > 0)
    {
if (render_pos == 28) return;
        // 下へ 1dot
        render_pos++;
        // 結果が奇数なら start_y を +1
        if (render_pos & 1)
            start_y = (start_y + 1) % RENDER_DY;
        logical_row = RENDER_DY - 1;                    // 画面の最下段が新規
        phys_y      = (start_y + logical_row) % RENDER_DY;
        rock_render_line(phys_y, logical_row);
    }
}
// ----------------------------------------------------------
// VRAM へ描画
//   start_y を先頭として、論理 0..RENDER_DY-1 を順に出力
// ----------------------------------------------------------
void map_draw(void)
{
    int logical_row;
    int src_y;
    unsigned char *curr_bufp, *top_bufp;
    unsigned char *pos = getscrnaddr(0, 4);
    if (render_pos & 1)
    {
        src_y     = start_y;
        curr_bufp = &render_buf_odd[src_y][0];
        top_bufp  = &render_buf_odd[0][0];
    }
    else
    {
        src_y     = start_y;
        curr_bufp = &render_buf_even[src_y][0];
        top_bufp  = &render_buf_even[0][0];
    }
    for (logical_row = 0; logical_row < RENDER_DY; logical_row++)
    {
        memcpy(pos, curr_bufp, RENDER_DX);
        pos += D_DX;
        curr_bufp += RENDER_DX;
        src_y++;
        if (src_y >= RENDER_DY)
        {
            src_y     = 0;
            curr_bufp = top_bufp;
        }
    }
}


いつものように、下記でビルドします。
 zcc +zx81 map.c key.c main.c -createa-app​


しかし、多少なりとも描画速度が速くなる事を期待したのですが。。。

結果は行コピーとほぼ変わらない程度でした。

非常に残念です。


開始位置を計算する割り算や余りなどの計算が増えたためと予想します。

これは、まあ仕方ないですね。

あとはアセンブラ化して高速化してみます。







お気に入りの記事を「いいね!」で応援しよう

最終更新日  2026.04.07 18:31:20
コメント(0) | コメントを書く
[ZX81C言語でのプログラム開発] カテゴリの最新記事


【毎日開催】
15記事にいいね!で1ポイント
10秒滞在
いいね! -- / --
おめでとうございます!
ミッションを達成しました。
※「ポイントを獲得する」ボタンを押すと広告が表示されます。
x
X

© Rakuten Group, Inc.
X
Design a Mobile Website
スマートフォン版を閲覧 | PC版を閲覧
Share by: