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
Citer : Posté le 10/02/2020 10:15 | #
Truly interesting. The assembler is on crack I guess. xD
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:
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...
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_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?
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.
As far as I know you can't, this happens transparently within GetKey().
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.
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.
Check whether OS is in version 3.x.
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++;
}
}
}
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.
Citer : Posté le 15/02/2020 09:50 | # | Fichier joint
{
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.b r0, @r2 ;*LCD_data_register = (byte)word
shlr8 r0
mov.b r0, @r2 ;*LCD_data_register = (byte)word
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
Citer : Posté le 15/02/2020 10:09 | #
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.
Citer : Posté le 15/02/2020 12:16 | # | Fichier joint
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
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
Citer : Posté le 15/02/2020 12:36 | #
I shall start coding that tomorrow! :P
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
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.
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
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
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!
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?
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.
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?
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.
Look into the CPG registers which hold the settings. It's not that hard.
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?
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.
Citer : Posté le 16/02/2020 02:59 | #
Thanks!
Still getting close to completing it now
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
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?
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.
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