Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » Mandelbrot Generator
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Mandelbrot Generator

Posté le 15/06/2019 10:38

Hello allô

Default 1x zoom takes 7sec
Max zoom takes around 5-10min
It has a max zoom of 2^50: over one Quadrillion!
Going over 2^48 can be rather buggy
This is because numbers are limited to the 8 byte double variables

Attached file is both SH4 and SH3 compatible: MANDEL.G1A

This does need the 'MonochromeLib' libs the code comes with it now

Controls
[-] Zoom out
[+] Zoom in
[F1] Hide/show HUD which contains Cords, Zoom level and Max Iterations. (Heads Up Display)
[F2] Changes colours of camera rectangle: Black, White & Inverted
[AC] Resets screen back to default state
[EXE] Draw set
[EXIT] Stop drawing the Mandelbrot (If it's taking too long)
[MENU] Return to the menu screen
[REPLAY] Move camera rectangle around (Arrow Keys: [LEFT], [RIGHT], [UP], [DOWN])

How can I optimize this code to run faster or zoom in further?

#include "fxlib.h"
#include "stdio.h"

#define TRUE 1
#define FALSE 0

#define ML_vram_adress (*(sc_cpv)sc0135)

typedef enum { ML_TRANSPARENT = -1, ML_WHITE, ML_BLACK, ML_XOR, ML_CHECKER } ML_Color;
typedef char* (*sc_cpv)(void);
const unsigned int sc0135[] = { 0xD201D002, 0x422B0009, 0x80010070, 0x0135 };

unsigned int key;                //pause until key press
int kcode1, kcode2;                //row & col keycode for Bkey_GetKeyWait()
char unused;                    //unused (cause CASIO dumb dumb)
unsigned short dispX, dispY;    //cords on display when drawing mandelbrot

void ML_clear_vram() {
    int i, end, * pointer_long, vram;
    char* pointer_byte;
    vram = (int)ML_vram_adress();
    end = 4 - vram & 3;
    pointer_byte = (char*)vram;
    for (i = 0; i < end; i++) pointer_byte[i] = 0;
    pointer_long = (int*)(vram + end);
    for (i = 0; i < 255; i++) pointer_long[i] = 0;
    pointer_byte += 1020 + end;
    end = vram & 3;
    for (i = 0; i < end; i++) pointer_byte[i] = 0;
}

void ML_display_vram() {
    char* LCD_register_selector = (char*)0xB4000000, * LCD_data_register = (char*)0xB4010000, * vram;
    int i, j;
    vram = ML_vram_adress();
    for (i = 0; i < 64; i++) {
        *LCD_register_selector = 4;
        *LCD_data_register = i | 192;
        *LCD_register_selector = 4;
        *LCD_data_register = 0;
        *LCD_register_selector = 7;
        for (j = 0; j < 16; j++)
            *LCD_data_register = *vram++;
    }
}

void ML_display_vram_row(int row) {            //faster than ML_display_vram() which displays the entire screen instead of a single row
    unsigned char i;
    char* LCD_register_selector = (char*)0xB4000000, *LCD_data_register = (char*)0xB4010000, *vram;
    vram = (row << 4) + ML_vram_adress();
    *LCD_register_selector = 4;
    *LCD_data_register = row | 192;
    *LCD_register_selector = 4;
    *LCD_data_register = 0;
    *LCD_register_selector = 7;
    for (i = 0; i < 16; i++)
        * LCD_data_register = *vram++;
}

void ML_horizontal_line(int y, int x1, int x2, ML_Color color) {
    int i;
    char checker;
    char* vram = ML_vram_adress();
    if (y & ~63 || (x1 < 0 && x2 < 0) || (x1 > 127 && x2 > 127))
        return;
    if (x1 > x2) {
        i = x1;
        x1 = x2;
        x2 = i;
    }
    if (x1 < 0)
        x1 = 0;
    if (x2 > 127)
        x2 = 127;
    switch (color) {
        case ML_BLACK:
            if (x1 >> 3 != x2 >> 3) {
                vram[(y << 4) + (x1 >> 3)] |= 255 >> (x1 & 7);
                vram[(y << 4) + (x2 >> 3)] |= 255 << 7 - (x2 & 7);
                for (i = (x1 >> 3) + 1; i < x2 >> 3; i++)
                    vram[(y << 4) + i] = 255;
            } else
                vram[(y << 4) + (x1 >> 3)] |= (255 >> (x1 % 8 + 7 - x2 % 8)) << (7 - (x2 & 7));
            break;
        case ML_WHITE:
            if (x1 >> 3 != x2 >> 3) {
                vram[(y << 4) + (x1 >> 3)] &= 255 << 8 - (x1 & 7);
                vram[(y << 4) + (x2 >> 3)] &= 255 >> 1 + (x2 & 7);
                for (i = (x1 >> 3) + 1; i < x2 >> 3; i++)
                    vram[(y << 4) + i] = 0;
            } else
                vram[(y << 4) + (x1 >> 3)] &= (255 << 8 - (x1 & 7)) | (255 >> 1 + (x2 & 7));
            break;
        case ML_XOR:
            if (x1 >> 3 != x2 >> 3) {
                vram[(y << 4) + (x1 >> 3)] ^= 255 >> (x1 & 7);
                vram[(y << 4) + (x2 >> 3)] ^= 255 << 7 - (x2 & 7);
                for (i = (x1 >> 3) + 1; i < (x2 >> 3); i++)
                    vram[(y << 4) + i] ^= 255;
            } else
                vram[(y << 4) + (x1 >> 3)] ^= (255 >> ((x1 & 7) + 7 - (x2 & 7))) << (7 - (x2 & 7));
            break;
        case ML_CHECKER:
            checker = (y & 1 ? 85 : 170);
            if (x1 >> 3 != x2 >> 3) {
                vram[(y << 4) + (x1 >> 3)] &= 255 << 8 - (x1 & 7);
                vram[(y << 4) + (x2 >> 3)] &= 255 >> 1 + (x2 & 7);
                vram[(y << 4) + (x1 >> 3)] |= checker & 255 >> (x1 & 7);
                vram[(y << 4) + (x2 >> 3)] |= checker & 255 << 7 - (x2 & 7);
                for (i = (x1 >> 3) + 1; i < x2 >> 3; i++)
                    vram[(y << 4) + i] = checker;
            } else {
                vram[(y << 4) + (x1 >> 3)] &= (255 << 8 - (x1 & 7)) | (255 >> 1 + (x2 & 7));
                vram[(y << 4) + (x1 >> 3)] |= checker & (255 >> (x1 % 8 + 7 - x2 % 8)) << (7 - (x2 & 7));
            }
            break;
    }
}

void ML_vertical_line(int x, int y1, int y2, ML_Color color) {
    int i, j;
    char checker, byte, * vram = ML_vram_adress();
    if (x & ~127 || (y1 < 0 && y2 < 0) || (y1 > 63 && y2 > 63)) return;
    if (y1 > y2) {
        int tmp = y1;
        y1 = y2;
        y2 = tmp;
    }
    if (y1 < 0) y1 = 0;
    if (y2 > 63) y2 = 63;

    i = (y1 << 4) + (x >> 3);
    j = (y2 << 4) + (x >> 3);
    switch (color) {
        case ML_BLACK:
            byte = 128 >> (x & 7);
            for (; i <= j; i += 16)
                vram[i] |= byte;
            break;
        case ML_WHITE:
            byte = ~(128 >> (x & 7));
            for (; i <= j; i += 16)
                vram[i] &= byte;
            break;
        case ML_XOR:
            byte = 128 >> (x & 7);
            for (; i <= j; i += 16)
                vram[i] ^= byte;
            break;
        case ML_CHECKER:
            byte = 128 >> (x & 7);
            checker = y1 & 1 ^ x & 1;
            for (; i <= j; i += 16) {
                if (checker) vram[i] &= ~byte;
                else vram[i] |= byte;
                checker = !checker;
            }
            break;
    }
}

void ML_pixel(int x, int y, ML_Color color) {
    char* vram = ML_vram_adress();
    if (x & ~127 || y & ~63) return;
    switch (color) {
        case ML_BLACK:
            vram[(y << 4) + (x >> 3)] |= 128 >> (x & 7);
            break;
        case ML_WHITE:
            vram[(y << 4) + (x >> 3)] &= ~(128 >> (x & 7));
            break;
        case ML_XOR:
            vram[(y << 4) + (x >> 3)] ^= 128 >> (x & 7);
            break;
        case ML_CHECKER:
            if (y & 1 ^ x & 1) vram[(y << 4) + (x >> 3)] &= ~(128 >> (x & 7));
            else vram[(y << 4) + (x >> 3)] |= 128 >> (x & 7);
            break;
    }
}

double divByPow(double n, double x, int p) {        //Divide OR Times n by x, p times (n / x^p): used for numbers bigger than 2^32 (int limit)
    if (p < 0)
        for (; p < 0; p++)
            n *= x;
    else
        for (; p > 0; p--)
            n /= x;
    return n;
}

void stop(void) {            //stops drawing set if user presses [EXIT] or [MENU]
    if (Bkey_GetKeyWait(&kcode1, &kcode2, 1, 0, 1, &unused))
        if (kcode1 == 4 && (kcode2 == 8 || kcode2 == 9)) {
            dispX = 128;    //Very hacky stop function
            dispY = 64;
        }
}

int AddIn_main(int isAppli, unsigned short OptionNum) {        //Main function
    unsigned int graphZoom = 1;                //zoom level for graph
    char screenZoom;                        //zoom level on screen (rectangle)
    int screenX1, screenX2;                    //corner X cords for drawing rectangle to screen
    int screenY1, screenY2;                    //corner Y cords for drawing rectangle to screen
    unsigned char string[1];                //Used in converting int/double to char
    char HUD = TRUE;                        //Heads Up Display: Cords, Zoom level & Max iteration: toggle with [F1]
    char colour = ML_XOR;                    //Colour of rectangle: Black, White or Inverted
    int screenX, screenY;                    //offset cords on screen from 0,0 for rectangle
    double graphX = 0, graphY = 0;            //cords on graph - where to center mandelbrot
    double graphMove;                        //amount graphX & Y changes by when moving rectangle around
    int screenMove;                            //amount screenX & Y changes by when moving rectangle around with arrow keys
    short tempPixel = 0;                    //Write pixels to temp variable then write the entire 2bytes to VRAM all at once

    register double zr, zi;                    //zr is real, zi imaginary
    register double zr2, zi2;                //zr2 = zr^2, zi2 = zi^2
    register double x1 = -2.0;                //bounding box cords on graph
    register double x2 = 2.0;                //bounding box cords on graph
    register double y1 = -1.0;                //bounding box cords on graph
    register double y2 = 1.0;                //bounding box cords on graph
    register double x, y;                    //pixel cords on graph tested if in set
    register double xIsz, yIsz;                //amount x/y increases by when ploting graph
    register unsigned short iMax = 32;        //max iterations
    register unsigned short i;                //iterations

    while (TRUE) {
        register char* vram = ML_vram_adress();

        SetTimer(1, 200, stop);
        ML_clear_vram();
        ML_display_vram();

        xIsz = (x2 - x1) / 128;
        yIsz = (y2 - y1) / 64;

        y = y1;
        for (dispY = 0; dispY < 64; dispY++) {
            x = x1;
            y += yIsz;
            for (dispX = 0; dispX < 128; dispX++) {
                zr = x;
                zi = y;
                for (i = 0; i < iMax; i++) {
                    zr2 = zr * zr;
                    zi2 = zi * zi;
                    if (zr2 + zi2 > 4)
                        break;
                    zi = zr * zi;
                    zi += zi + y;
                    zr = zr2 - zi2 + x;
                }
                tempPixel = (tempPixel << 1) | (i == iMax);
                if ((dispX & 7) == 7)
                    *vram++ = tempPixel;
                x += xIsz;
            }
            ML_display_vram_row(dispY);
        }
        SaveDisp(1);
        KillTimer(1);
        screenX = 0;
        screenY = 0;
        screenZoom = 1;
        Bkey_GetKeyWait(&kcode1, &kcode2, 2, 1, 1, &unused);
        do {
            GetKey(&key);
            screenMove = screenZoom > 4 ? 1 : divByPow(16, 2, screenZoom);
            graphMove = screenZoom > 4 ? divByPow(1, 2, graphZoom - (double)screenZoom) : divByPow(16, 2, graphZoom);
            switch (key) {
                case KEY_CHAR_PLUS:
                    if (graphZoom < 51) {
                        graphZoom++;
                        screenZoom++;
                    }
                    break;
                case KEY_CHAR_MINUS:
                    if (graphZoom) {
                        graphZoom--;
                        screenZoom--;
                    }
                    break;
                case KEY_CTRL_UP:
                    screenY -= screenMove;
                    graphY -= graphMove;
                    break;
                case KEY_CTRL_DOWN:
                    screenY += screenMove;
                    graphY += graphMove;
                    break;
                case KEY_CTRL_LEFT:
                    screenX -= screenMove;
                    graphX -= graphMove;
                    break;
                case KEY_CTRL_RIGHT:
                    screenX += screenMove;
                    graphX += graphMove;
                    break;
                case KEY_CTRL_F1:
                    HUD = !HUD;
                    break;
                case KEY_CTRL_F2:
                    if (colour)
                        colour--;
                    else
                        colour = ML_XOR;
                    break;
                case KEY_CTRL_F3:
                    //Gray scale, by refreshing screen multiple times per sec at different max iterations (iMax)
                    break;
                case KEY_CTRL_AC:
                    graphZoom = 1;
                    graphX = 0;
                    graphY = 0;
                    screenZoom = 1;
                    screenX = 0;
                    screenY = 0;
                    key = KEY_CTRL_EXE;
                    break;
            }
            RestoreDisp(1);
            iMax = 8 * (graphZoom + 3);

            if (screenZoom < 8) {
                screenX1 = 65 - divByPow(128, 2, screenZoom) + screenX;
                screenX2 = 62 + divByPow(128, 2, screenZoom) + screenX;
                screenY1 = 32 - (screenZoom > 6 ? 1 : divByPow(64, 2, screenZoom)) + screenY;
                screenY2 = 31 + (screenZoom > 6 ? 0 : divByPow(64, 2, screenZoom)) + screenY;
                ML_horizontal_line(screenY1, screenX1, screenX2, colour);
                ML_horizontal_line(screenY2, screenX1, screenX2, colour);
                ML_vertical_line(screenX1 - 1, screenY1, screenY2, colour);
                ML_vertical_line(screenX2 + 1, screenY1, screenY2, colour);
            } else
                ML_pixel(screenX + 64, screenY + 31, colour);

            x1 = divByPow(-4, 2, graphZoom) + (0.03125 * graphX);
            x2 = divByPow(4, 2, graphZoom) + (0.03125 * graphX);
            y1 = divByPow(-2, 2, graphZoom) + (0.03125 * graphY);
            y2 = divByPow(2, 2, graphZoom) + (0.03125 * graphY);

            if (HUD == TRUE) {
                sprintf(&string, "X1:%f", x1);
                PrintMini(0, 0, string, 0);
                sprintf(&string, "Y1:%f", y1);
                PrintMini(0, 6, string, 0);
                sprintf(&string, "X2:%f", x2);
                PrintMini(81, 53, string, 0);
                sprintf(&string, "Y2:%f", y2);
                PrintMini(81, 59, string, 0);
                sprintf(&string, "MaxI:%u", iMax);
                PrintMini(0, 53, string, 0);
                if (graphZoom > 32)
                    sprintf(&string, "Zoom:2^%ux", graphZoom - 1);
                else
                    sprintf(&string, "Zoom:%ux", (int)divByPow(1, 2, -graphZoom + 1));
                PrintMini(0, 59, string, 0);
            }

            ML_display_vram();

        } while (key != KEY_CTRL_EXE);
    }
    return 0;
}


#pragma section _BR_Size
unsigned long BR_Size;
#pragma section
#pragma section _TOP
int InitializeSystem(int isAppli, unsigned short OptionNum) {
    return INIT_ADDIN_APPLICATION(isAppli, OptionNum);
}
#pragma section


Fichier joint


Précédente 1, 2, 3, 4, 5, 6, 7, 8 Suivante
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 10/02/2020 10:15 | #


Im able to type shll8 r1, r5 without any errors

Truly interesting. The assembler is on crack I guess. xD

Without using mov.w or mov.l
Is it possible to type mov #255, r0 without it becoming r0 = 0xFFFFFFFF (-1)?

The range of a mov #immediate, rn is only -128...127. If you want another value you either need to load it using mov.w/l or to trick.

In your specific case you can do this, which avoids the memory reference:

mov #255, r0
extu.b r0, r0

Note that when you do mov.b or mov.w from memory, only the bottom bits are loaded, and so it is usual to follow mov.b with ext[us].b and mov.w with ext[us].w to make sure the top bits have the correct value. Forgetting to do this results in insidious bugs...
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 14/02/2020 09:24 | # | Fichier joint


I did a small overhaul of the code

Mandelbrot_64bitFP.zip

Controls
[-] Zoom out
[+] Zoom in
[F1] Hide/show HUD which contains Cords, Zoom level and Max Iterations. (Heads Up Display)
[F2] Changes colours of camera rectangle: Transparent, White Black, Inverted (XOR) and Checkered
[F3] Brings up the submenu to change the formula for max iterations
[F4] Gray Engine
[F5] Load/Save current coordinates (Currently only displays cords on-screen in raw hex format)
[F6] Enable/Disable instant draw mode. Draws the mandelbrot straight away after pressing [+], [-] or [REPLAY] (Recommend overclocking with Ftune3) (What should I call this feature? What to put on the [F6] button on screen?)
[AC] Resets everything back to default state
[EXE] Draw set
[EXIT] Go back
[0] - [9] Enter number
[MENU] Return to the main menu screen
[REPLAY] Move camera rectangle around (Arrow Keys: [LEFT], [RIGHT], [UP], [DOWN])
[SHIFT] + [AC] Power off the calculator
[ALPHA] + [AC] Power off the calculator without displaying the logo screen (faster)
[SHIFT] + [EXIT] Quit the program
[EXIT] || [MENU] || [AC] Stop drawing the Mandelbrot (If it's taking too long)

Whats a better looking GUI I could do for the max iterations?
A name for [F6]?
With the gray engine, the iterations used to determine what colour it should be is based off max iterations - N. With N being 0 for black, infinite for white and roughly 30 for light gray and 24 for dark. But the light and dark gray values need to change depending on what part of the Mandel you zoom into. And if you have too higher max iterations the 255 char max value isn't enough to store the values (doesn't run out until like 8k iterations). (maybe I can change it to shorts, but IDK how much memory there is there for it. Currently, it's at 8kilobytes, 8192 8bit bytes, 65536 bits). Maybe I could look at all the iteration values of each pixel and grab the median of it to base the light and dark gray off it. ([X] and [/] to switch between changing Dark and Light iterations. [(] and [)] add / minus 1)
Reducing the size of the addin?
How to detect when the user comes back from the Main menu via GetKey()?
I can detect when leaving and stop the timer controlling the Gray engine
Otherwise, the gray engine will still run after exiting to the main menu

Ajouté le 14/02/2020 à 21:40 :
Saw your comment in Immortal's game

So currently my program isn't compatible with Graph 35+E II
and all I need to do is change a few values?
*LCD_register_selector = 8;  // 4
*LCD_data_register = i|128;  // 192
*LCD_register_selector = 8;  // 4
*LCD_data_register = 4;      // 0
*LCD_register_selector = 10; // 7

How to detect if its a Graph 35+E II vs anything else?
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 14/02/2020 23:21 | #


Your new update sounds good! Unfortunately I'm doing an internship currently and my only mono calc is the Graph 35+E II so... I've tried, but I can't test it.

I guess the F6 feature could be called real-time rendering so you might put RT as a label?

Good luck with the gray. It'd be nice if you can pull off a good-looking balance.

I'm not sure exactly which problem you are running into with the potential overflow on 8-bit number. What I can tell is that on SH3 if you need more than 8 kB in a buffer you need to allocate it with malloc() because there is no stable memory area that will give you this much. Reducing the size of the add-in file itself will only save ROM and won't help you here.

How to detect when the user comes back from the Main menu via GetKey()?

As far as I know you can't, this happens transparently within GetKey().

I can detect when leaving and stop the timer controling the Gray engine
Otherwise the gray engine will still run after exiting to the manin menu

Then you can detect the MENU key press with something else than GetKey(), stop the timer and then inject MENU into the key buffer and start GetKey(). You can't, however, detect when the user comes back into the add-in. In addition GetKey() will cause Bdisp_PutDisp_DD() and nothing else so you VRAM needs to be the system VRAM. Games usually use a pause screen where the gray engine is stopped to avoid the artifact.

So currently my program isn't compatible with Graph 35+E II
and all I need to do is change a few values?

This is correct. If you use other direct-display functions of MonochromeLib you will need to change them as well.

How to detect if its a Graph 35+E II vs anything else?

Check whether OS is in version 3.x.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 00:56 | #


Is this good enough?

void System_GetOSVersion(unsigned char version[10]); //Syscal 0x02EE

void ML_display_vram() {
    char* LCD_register_selector = (char*)0xB4000000;
    char* LCD_data_register = (char*)0xB4010000;
    char* vram = ML_vram_adress();
    unsigned char OS[10];
    int i, j;
    
    System_GetOSVersion(OS);

    if (OS[1] == '3') {
        for (i = 0; i < 64; i++) {
            *LCD_register_selector = 8;
            *LCD_data_register = i | 128;
            *LCD_register_selector = 8;
            *LCD_data_register = 4;
            *LCD_register_selector = 10;
            for (j = 0; j < 16; j++)
                *LCD_data_register = *vram++;
        }
    } else {
        for (i = 0; i < 64; i++) {
            *LCD_register_selector = 4;
            *LCD_data_register = i | 192;
            *LCD_register_selector = 4;
            *LCD_data_register = 0;
            *LCD_register_selector = 7;
            for (j = 0; j < 16; j++)
                *LCD_data_register = *vram++;
        }
    }
}

Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 08:45 | #


Yes, this should be exactly what you need. Here's the source in gint and the disassembled syscall if you want to know more.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 09:50 | # | Fichier joint


static int variant(void)
{
    char os[11];
    __os_version(os);
    return (os[1] == '3');
}

Why is your char 11 long?
In System_GetOSVersion it says Space for 10 characters is required. and the output seems to only be 10 chars 00.00.0000

mov.w    @r4+,          r0             ;word = *buffer++
mov.b    r0,            @r2            ;*LCD_data_register = (byte)word
shlr8    r0
mov.b    r0,            @r2            ;*LCD_data_register = (byte)word
Is that faster than this?
mov.b    @r4+,          r0             ;byte = *buffer++
mov.b    r0,            @r2            ;*LCD_data_register = byte
mov.b    @r4+,          r0             ;byte = *buffer++
mov.b    r0,            @r2            ;*LCD_data_register = byte


I managed to write a Display_Gray_Buffer(); in C that ran exactly the same speed as I had written it in ASM (Loop speed)

Should work with Graph 35+E II now
Mandelbrot_64bitFP.zip
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 10:09 | #


Why is your char 11 long?

Because I don't know if it's NUL-terminated and I have no reason to spare a byte of stack.

Yes, I believe the second version that does only one memory access is technically faster. However VRAM is not 4-aligned so this will become troublesome pretty quickly. You can load unaligned with movua.l, and in this case you can even make that a longword. But it won't change a thing overall...

This is because, as you might know, device communication is slow. Let me give you some figures to compare :
• Clearing 1024 bytes of VRAM with longword accesses takes 6 µs.
• Sending1024 bytes of VRAM to the T6K11 takes 2500 µs.

As you can guess, optimizing the VRAM access is not going to make it any faster.

It's starting to work on the Graph 35+E II, but I suspect you have used some direct-DD functions which you have not yet adapted for Graph 35+E II. This is because certain operations such as going "real-time" confuses the screen and mixes up vertical lines, an effect that persists even after leaving the add-in and that corresponds to what happens when ML_display_vram() is not adapted.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 12:16 | # | Fichier joint


As you can guess, optimizing the VRAM access is not going to make it any faster.
Every tiny little bit helps

I had made ML_display_vram() and Gray_Display_DD() compatible
But forgot about ML_clear_display() (which is only used when turning the calc off)
and when drawMandelASM() draws to the screen (while it computes the mandelbrot)

Real-Time doesn't use ML_display_vram() (which seems to reset the screen based on what you said)
so when drawMandelASM() is called, it ruins the display
and unless you turn RT off again, ML_display_vram() won't be called again and exiting out of the program doesn't call ML_display_vram() either

This work now? Mandelbrot_64bitFP.zip
Made ML_clear_display() and drawMandelASM() compatible
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 12:27 | #


Much better, thank you!

I have a suggestion for the real-time mode: unless you zoom in or out, you are just moving around with the arrow keys and each frame is close to the previous one. In this situation, there is really no need to recompute the whole screen since just a couple of new pixels are actually added.

I zoomed down to a 16 million scale factor and it's still pretty smooth. Well done
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 12:36 | #


no need to recompute the whole screen since just a couple of new pixels are actually added.
That is possible to do
I shall start coding that tomorrow! :P

I zoomed down to a 16 million scale factor and it's still pretty smooth. Well done
Thanks
max zoom is 2^53 => 9*10^15 => 90 Quintillion => 9,007,199,254,740,992 times zoom

Have you tried out GrayScale yet?
and can you tell me the timings for near-perfect grays (top left corner after pressing [F4]) for the Graph 35+E II

Ajouté le 15/02/2020 à 12:40 :
Whats the movua.l instruction?
It doesn't show up in https://bible.planet-casio.com/common/hardware/mpu/sh3_manual.pdf
7.1.1 Data Transfer Instructions
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 12:40 | #


Ah yes! I have tried gray but did not report on it.

Unfortunately, gray timings on the Graph 35+E II are different from the timings on other models. I have to address that in gint too. None of the settings available in the top left corner of the F4 menu even produce an illusion of gray on the Graph 35+E II... it's just flicker and v-sync lines.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 13:11 | # | Fichier joint


These are the timings when I've overclocked my calc 542100 and without overclocking it's 062500
The emulator works at around 200000 (tho its just flicker, not gray)

The number is just passed into the Gray_Delay_ASM() function
_Gray_Delay_ASM:                    ;Gray_Delay_ASM(unsigned int instructions)
    tst        r4,            r4
loop
    bf/s    loop
    dt        r4
    rts
    nop

runs 3 instructions times the input number
so 542000 * 3 = 1626000 instructions worth of delay

Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 13:16 | #


Oh I see, you can adjust it like that! Sorry I missed it.

356020 is somewhat decent, there are v-sync lines but we don't see them on the fractal.

Gray looks so great here!
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 13:36 | #


Sorry
Just having the number there isn't very intuitive
What's a single word (or symbols) I can put there that would make you think you can change it?
and know exactly how it works

Maybe try a multiple of 356020 like 712040 or 178010
There are multiple numbers that work, they just give different gray levels (some are darker than others)
Can you send a pic/gif/vid of your gray, please?

I found plugging my calc into power (via the USB cable into a pc) reduced a lot of "random" v-sync lines

Is there a super simple way to detect an overclock of the CPU?
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 13:49 | #


It's pretty intuitive as it is, I just got stupid for a moment. Never mind.

Sure, here's a highlight : https://linx.breizh.pm/selif/v4g6h3lo.mp4



That's my best. I have tried all 100 combinations for the two first digits (the third doesn't change the general aspect), and haven't found anything better. The video is pretty good, in practive I don't see that much flickering. But yeah, it's not ideal...

This was on battery.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 15/02/2020 14:14 | #


Those grays and vsync lines
On my calc it looks way better
as you saw in the image above
If you look closely, you will see horizontal bands of slightly lighter and darker grays
They slower flicker downwards
which you can see easier in real life. (but isn't too bad)
The problem is I'm using a mixture of milliseconds and instruction delays

You can change how much of the LIGHT and DARK gray area is shaded on screen
LIGHT:30
DARK:24

Is it possible to make a timer based on number of instructions instead of number of milliseconds?
Lephenixnoir Hors ligne Administrateur Points: 24632 Défis: 170 Message

Citer : Posté le 15/02/2020 14:35 | #


Honestly when exploring the fractal there is not a lot of gray on screen, it looks good enough. But otherwise that's not really clean, I agree. I tried changing the LIGHT and DARK areas, it looks fine with all settings. As long as the gray is not completely depressing it will work out in the end.

Is there a super simple way to detect an overclock of the CPU?

Look into the CPG registers which hold the settings. It's not that hard.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Sentaro21 Hors ligne Membre Points: 878 Défis: 0 Message

Citer : Posté le 16/02/2020 02:45 | #


I'm very impressed with the wonderful updates.

About the optimal grayscale timings for overclocked calculators and emulators ,
Can it derive from the screen update FPS?

Je continue à développer C.Basic. (Il est compatible avec Basic Casio.)
Overclocking utilitaire Ftune/Ptune2/Ptune3 est également disponible.
Si vous avez des questions ou un rapport de bogue, n'hésitez pas à me le faire savoir.
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 16/02/2020 02:59 | #


Thanks!
Still getting close to completing it now

Can it derive from the screen update FPS?
I thought the screen didn't run at a specific refresh rate?
And whats the simplest way to get the clock frequency (just so it works by default with overclocking)

Currently it uses SetTimer(id_1, 25ms, drawGray)
and loops instructions to create a delay between drawing Light gray and dark gray

The problem is I'm mixing milliseconds and instruction cycles together
So when the clock speed changes, the ratio of dark gray to light gray doesn't stay constant

I need to only use time or only clock cycles
But I need interrupts (which is time only??) and very precise delay function (currently it seems I can only use instruction cycles)
Is it possible to run interrupts that are based on number of clock cycles instead of number of milliseconds?
(or a sub-millisecond timer)

And the 25ms doesn't match perfectly with the amount of time the light and dark gray have to be on screen
Like light gray needs 10ms (IDK actual number) and dark needs 15.1ms which does not add up to 25ms
but if it's not 15.1ms, then there will be vsync lines and/or flickering
Sentaro21 Hors ligne Membre Points: 878 Défis: 0 Message

Citer : Posté le 16/02/2020 05:31 | #


Ah,Ok!

Can the 1/32768 timer be used for mlliseconds delays?

Or
The processing time of RTC_GetTicks() seems to be almost constant waiting time regardless of the operating clock.
This is used to determine the pitch of C.Basic Beep command.

Or,
Rather than responding to various overclocking speeds,
How about fixing the operation clock?

Je continue à développer C.Basic. (Il est compatible avec Basic Casio.)
Overclocking utilitaire Ftune/Ptune2/Ptune3 est également disponible.
Si vous avez des questions ou un rapport de bogue, n'hésitez pas à me le faire savoir.
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 16/02/2020 05:49 | #


What is this 1/32768 timer?

I think I did try RTC_GetTicks(), but couldn't get it working (errors)
I thought it was just cause of my calculator, but you say C.Basic uses it

If the operating speed was fixed, I would have to revert it back to the overclocked speed when the mandelbrot is computed
And it would be different across the different models?

How to create an interrupt (without breaking all others) with a smaller time than 25ms?

Maybe I don't use any interrupts, or timers and just make it with "clock cycle" based delays only
Précédente 1, 2, 3, 4, 5, 6, 7, 8 Suivante

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 52 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd