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 ··· 5, 6, 7, 8
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
Sentaro21 Hors ligne Membre Points: 877 Défis: 0 Message

Citer : Posté le 16/02/2020 06:47 | # | Fichier joint


Redcmd a écrit :
What is this 1/32768 timer?

1/32768 timer is only for SH4A model,
You can use a count-up timer by default.
#define P7305_EXTRA_TMU5_COUNT 0xA44D00D8
*(unsigned int*)P7305_EXTRA_TMU5_COUNT


Redcmd a écrit :
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

The following is an example of using in C.Basic that mimics the microseconds waiting SysCall in Prizm.
void CMT_Delay_micros( int n ) {
    int i,j;
    volatile int t=0;
    for ( i=0; i<n; i++ ) for ( j=0; j<1; j++ ) t+=RTC_GetTicks();
}


Redcmd a écrit :
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?

Dynamic clock switching is easy if the operation target calculator is limited to SH4A.
This allows you to set Ftune2 default settings directly.
[Fichier joint]:Ftune2_simple.zip

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

Sorry,I don't know how to change the minimum interrupt time.
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 07:20 | #


CASIO really has made it hard for me to do this
There's no 'perfect', always works in every case function

I want this to be compatible with Graph 35+EII, SH3 and SH4 (and more if possible)
My current setup, SetTimer() works fine on my calc SH4, but breaks badly on the Graph 35+EII
For some reason?

The following is an example of using in C.Basic that mimics the microseconds waiting SysCall in Prizm.
Why the j for loop? and why t volatile?
Sentaro21 Hors ligne Membre Points: 877 Défis: 0 Message

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


Redcmd a écrit :
I want this to be compatible with Graph 35+EII, SH3 and SH4 (and more if possible)
My current setup, SetTimer() works fine on my calc SH4, but breaks badly on the Graph 35+EII
For some reason?

I think it is best to create a dedicated routine for each model.

Why the j for loop? and why t volatile?

Looping to create a delay of about 1 microsecond.
volatile is to prevent deletion by optimization.
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.
Lephenixnoir En ligne Administrateur Points: 24227 Défis: 170 Message

Citer : Posté le 16/02/2020 09:01 | #


Good catch, Sentaro. Indeed you can try and use the 32768 Hz hardware timer. However, as I explained before, you cannot get an interrupt out of it. What I missed is that Redmcd is already doing active waiting here, so doing it with a hardware timer is not going to change much.

Edit: There is one 32768 Hz timer on SH3 but it's used to power SetTimer().

Redcmd, would you mind if I made a few tests with gint? I have a few ideas I'd like to try, but I don't want to make it sound like I'm competing with you.
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 16/02/2020 09:59 | #


Go ahead :ThumbsUp:
One single person can’t come with every idea possible

There is one 32768 Hz timer on SH3 but it's used to power SetTimer().
Because SetTimer uses it, so we can’t? (or at least not without breaking every interrupt?)
Sentaro21 Hors ligne Membre Points: 877 Défis: 0 Message

Citer : Posté le 16/02/2020 10:46 | #


@Lephenixnoir
Thanks!
Is it possible to read the value of 32768 Hz timer in SH3?
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.
Lephenixnoir En ligne Administrateur Points: 24227 Défis: 170 Message

Citer : Posté le 16/02/2020 10:51 | #


Yes. You can read from 0xa44c0030. First is TSTR (1 byte), then 3 bytes gap, then TCOR (4 bytes), TCNT (4 bytes) and TCR (1 byte). The structure is the same as on SH4, but there is only one 32768 Hz, while there are six on SH4.

If you want to use this you will probably need to stop all timers of SetTimer() first, or observe the counter without reconfiguring the timer. The default constant should be about 820. Note that you can also use the normal hardware timers that are connected to the CPG and count at Pϕ/4. To the best of my knowledge they are not used too much, you can probably find an unused one automatically.

More information about the 32768 Hz timers is available in the Planète Casio bible.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Sentaro21 Hors ligne Membre Points: 877 Défis: 0 Message

Citer : Posté le 16/02/2020 11:54 | #


Thank you very much!
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 17/02/2020 10:20 | # | Fichier joint


What's 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

With doing this
mov.l    @r4+,          r0             ;long = *buffer++
mov.b    r0,            @r2            ;*LCD_data_register = (byte)long
shlr8    r0,                           ;long >>= 8;
mov.b    r0,            @r2            ;*LCD_data_register = (byte)long
shlr8    r0,                           ;long >>= 8;
mov.b    r0,            @r2            ;*LCD_data_register = (byte)long
shlr8    r0,                           ;long >>= 8;
mov.b    r0,            @r2            ;*LCD_data_register = (byte)long

VRAM being 1 aligned doesn't matter cause I'm not using it for Gray
But only problem is that the bytes are loaded to the display backwards
so instead of 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 it loads them like 4,3,2,1,8,7,6,5,12,11,10,9,16,15,14,13
Maybe I can just mix up the buffer so it gets unmixed when loaded to the display

for (i = 0; i < 1024; i += 4) {
        byte = Gray.VRAM.Dark[i + 0];
        Gray.VRAM.Dark[i + 0] = Gray.VRAM.Dark[i + 3];
        Gray.VRAM.Dark[i + 3] = byte;
        byte = Gray.VRAM.Dark[i + 1];
        Gray.VRAM.Dark[i + 1] = Gray.VRAM.Dark[i + 2];
        Gray.VRAM.Dark[i + 2] = byte;

        byte = Gray.VRAM.Light[i + 0];
        Gray.VRAM.Light[i + 0] = Gray.VRAM.Light[i + 3];
        Gray.VRAM.Light[i + 3] = byte;
        byte = Gray.VRAM.Light[i + 1];
        Gray.VRAM.Light[i + 1] = Gray.VRAM.Light[i + 2];
        Gray.VRAM.Light[i + 2] = byte;
}


Did a small GUI update and added that code above
Addin is slowly getting bigger: 34KB
MANDEL.G1A
Lephenixnoir En ligne Administrateur Points: 24227 Défis: 170 Message

Citer : Posté le 17/02/2020 13:25 | #


What's the movua.l instruction?

It's a unaligned move. It has been added in SH4 models so you need to look into the SH4 documentation.

It's basically movual.l @rm, rn (or movua.l @rm+, rn) and it loads four consecutive bytes from address rm into rn. When rm is a multiple of 4 it is equivalent to mov.l @rm, rn (or mov.l @rm+, rn). But if rm is not a multiple of 4, then it still loads four bytes from address rm while mov.l would fail with an address error.

There is no corresponding unaligned-write instruction.

But only problem is that the bytes are loaded to the display backwards (...)
Maybe I can just mix up the buffer so it gets unmixed when loaded to the display

Or you can sacrifice a few cycles and keep the order. You should compare performance if this matters to you, although all of this is about 0.25% of the total screen update time so it's not going to change much I believe...

mov.l @r4+, r0
swap.w r0, r0
swap.b r0, r0
mov.b r0, @r2
swap.b r0, r0
mov.b r0, @r2
swap.w r0, r0
swap.b r0, r0
mov.b r0, @r2
swap.b r0, r0
mob.b r0, @r2

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 12/09/2020 06:52 | #


Is it possible to test if the power cable (usb cable) is connected? and/or not running on battery?
When I connect my calc (9750) to power, the RTC clock seems to run faster
Kbd2 Hors ligne Membre Points: 269 Défis: 0 Message

Citer : Posté le 12/09/2020 06:59 | #


Take the batteries out whilst connected via USB.
Redcmd Hors ligne Membre Points: 380 Défis: 7 Message

Citer : Posté le 12/09/2020 07:01 | #


I mean from within software
Like a SYSCALL
But syscall Battery_GetStatus() returns 0 when on battery and power
Kbd2 Hors ligne Membre Points: 269 Défis: 0 Message

Citer : Posté le 12/09/2020 07:05 | #


Simon's battery syscall documentation does not list anything that would be able to check if the calc is on USB power - I suspect that's a circuitboard-level feature disconnected from the kernel.
Lephenixnoir En ligne Administrateur Points: 24227 Défis: 170 Message

Citer : Posté le 12/09/2020 10:21 | #


The A/DC will likely output a different recognizable pattern when running over USB.
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 12/09/2020 10:54 | #


I swaped out the Delay() function I was using in the gray engine
For the timer value at 0xA44D0038 (SH4)
Once the gray is tuned (no vsync lines etc) I can OC the calc, without having to retune it again
But when pluging into power, I get heaps of vsync lines and have to retune again
If I use the 0xA44D00D8 32768Hz timer value.
Pluging it in or running on battery doesn't desync the gray
But OC now does

Using the old Gint Demo program
The Timer/RTC comparison test stays at 100% Accuracy on battery
But slowly drops to 99.99% accurate on power once the timer hits roughly 0x0900
And 99.98% at around 0x1500
99.97% at 0x1b00 etc...

Here are some timer addresses (SH4) and some of the values I've seen on them:
0xA413FEC0; 0x00000000
0xA449000C; 0xFFFFFFFF
0xA4490018; 0xFFFFFFFF and 0x000167DD
0xA4490024; 0xFFFFFE33 // last digits flicker
0xA44D0038; 819 // Used by SetTimer and keyboard // 819 ticks = 25ms
0xA44D0058; 0 // set to 819 after restarting calc
0xA44D0078; 0 // set to 819 after restarting calc
0xA44D0098; 0 // set to 819 after restarting calc
0xA44D00B8; 0 - 9000 // Used when screen sharing to PC
0xA44D00D8; 32bit down counter // 32768Hz
https://bible.planet-casio.com/simlo/chm/v20/fx_7305_Registers.htm
https://bible.planet-casio.com/simlo/chm/v20/fxCG20_timer.htm
https://bible.planet-casio.com/lephenixnoir/etmu.html

Is it possible to make my own interrupt timer?
Like the SDK's SetTimer(). But with better timings other than just 25ms
Lephenixnoir En ligne Administrateur Points: 24227 Défis: 170 Message

Citer : Posté le 12/09/2020 11:14 | #


This is interesting. Unfortunately I don't know how this could be handled propertly. If it's the RTC, using a TMU might help. TMU-based versions of gint's gray engine do not produce different visual results when running on battery and USB power.

Is it possible to make my own interrupt timer?

No. Controlling interrupts is the basis for gint. There are three stages, probably none of which is a satisfying answer for you.
• You can take control of interrupts and handle only the timer (Revolution-FX method). Breaks everything else, mandatory reboot when add-in finishes.
• You can take control of interrupts, handle only the timer, and redirect the rest (Kristaba's auto-debugger method). Expect pain debugging the OS since the OS' interrupt handler will take back VBR control from you.
• You can take control of interrupts and handle everything (the gint method), but there's no point in reimplementing everything in your project.

However, there is a more viable way. You can start a TMU with interrupts disabled and just watch the counter run as you do with the ETMU. It will give similar results without you needing to care about interrupts at all.

TMU work almost exactly like ETMU, they just have a couple more settings. See the SH7724 documentation for details, or this tmu.h for a bit of reusable code. Basically you want to set eg. TMU0 to run on Pphi/64 or faster (most precise is Pphi/4), set the delay in TCOR and TCNT, and start watching. gint uses Pphi/64 with the following delays. If I remember correctly you only use one shade of gray but hopefully this can help you find good-looking settings.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Précédente 1, 2, 3 ··· 5, 6, 7, 8

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 72 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