From 92fd107478694c25fdc16c74817cdaa29e4eda2c Mon Sep 17 00:00:00 2001 From: Lephe Date: Thu, 21 Mar 2019 22:00:41 +0100 Subject: [PATCH] gintctl: first commit, still a mess but in progress --- .gitignore | 10 + Makefile | 106 +++++++ TODO | 1 + icon-cg-sel.png | Bin 0 -> 3005 bytes icon-cg-uns.png | Bin 0 -> 1426 bytes icon-fx.png | Bin 0 -> 259 bytes libfxcg.a | Bin 0 -> 1952 bytes main.c | 686 +++++++++++++++++++++++++++++++++++++++++ resources/pattern.png | Bin 0 -> 1444 bytes resources/pattern2.png | Bin 0 -> 7970 bytes src/gintctl.c | 23 ++ 11 files changed, 826 insertions(+) create mode 100644 .gitignore create mode 100755 Makefile create mode 100644 TODO create mode 100644 icon-cg-sel.png create mode 100644 icon-cg-uns.png create mode 100644 icon-fx.png create mode 100644 libfxcg.a create mode 100644 main.c create mode 100644 resources/pattern.png create mode 100644 resources/pattern2.png create mode 100644 src/gintctl.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea4a8f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Build directories +build.fx/ +build.cg/ + +# Targets +gintctl.g1a +gintctl.g3a + +# Full, heavier version of libfxcg +libfxcg-full.a diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..934dc42 --- /dev/null +++ b/Makefile @@ -0,0 +1,106 @@ +#! /usr/bin/make -f +# Makefile for the gint control add-in +#--- + +# +# Configuration +# + +# Compiler flags +cf := -mb -ffreestanding -nostdlib -Wall -Wextra -std=c11 -Os \ + -fstrict-volatile-bitfields +cf-fx := $(cf) -m3 -DFX9860G +cf-cg := $(cf) -m4-nofpu -DFXCG50 + +# Linker flags +lf-fx := -Tfx9860g.ld -lgint-fx -lgcc -Wl,-Map=build.fx/map +lf-cg := -Tfxcg50.ld -lgint-cg -lgcc -Wl,-Map=build.cg/map -L. -lfxcg + +dflags = -MMD -MT $@ -MF $(@:.o=.d) -MP +cpflags := -R .bss -R .gint_bss + +g1af := -i icon-fx.png -n gintctl --internal=@GINTCTL +g3af := -n basic:" " -i uns:icon-cg-uns.png -i sel:icon-cg-sel.png + +# +# File listings +# + +elf = $(dir $<)gintctl.elf +bin = $(dir $<)gintctl.bin +target-fx := gintctl.g1a +target-cg := gintctl.g3a + +# Source and object files +src := $(wildcard *.c) +res := $(wildcard resources/*) +obj-fx := $(src:%.c=build.fx/%.o) $(res:resources/%=build.fx/%.o) +obj-cg := $(src:%.c=build.cg/%.o) $(res:resources/%=build.cg/%.o) + +# Additional dependencies +deps-fx := icon-fx.png +deps-cg := icon-cg-uns.png icon-cg-sel.png + +# +# Build rules +# + +all: all-fx all-cg + +all-fx: $(target-fx) +all-cg: $(target-cg) + +$(target-fx): $(obj-fx) $(deps-fx) + + sh3eb-elf-gcc -o $(elf) $(obj-fx) $(cf-fx) $(lf-fx) + sh3eb-elf-objcopy -O binary $(cpflags) $(elf) $(bin) + fxg1a $(bin) -o $@ $(g1af) + +$(target-cg): $(obj-cg) $(deps-cg) + + sh4eb-elf-gcc -o $(elf) $(obj-cg) $(cf-cg) $(lf-cg) + sh4eb-elf-objcopy -O binary $(cpflags) $(elf) $(bin) + mkg3a $(g3af) $(bin) $@ + +# C sources +build.fx/%.o: %.c | build.fx/ + sh3eb-elf-gcc -c $< -o $@ $(cf-fx) $(dflags) +build.cg/%.o: %.c | build.cg/ + sh4eb-elf-gcc -c $< -o $@ $(cf-cg) $(dflags) + +# Images +build.fx/%.png.o: resources/%.png | build.fx/ + fxconv -i $< -o $@ name:$* +build.cg/%.png.o: resources/%.png | build.cg/ + @ echo -e "\e[31;1mWARNING: conversion for fxcg50 not supported yet\e[0m" + fxconv -i $< -o $@ name:$* + +%/: + @ mkdir -p $@ + +# +# Cleaning and utilities +# + +# Dependency information +-include $(shell find build* -name *.d 2> /dev/null) +build.fx/%.d: ; +build.cg/%.d: ; +.PRECIOUS: build.fx build.cg build.fx/%.d build.cg/%.d %/ + +clean: + @ rm -rf build* +distclean: clean + @ rm -f $(target-fx) $(target-cg) + +install-fx: $(target-fx) + p7 send -f $< +install-cg: $(target-cg) + @ while [[ ! -h /dev/Prizm1 ]]; do sleep 1; done + @ mount /dev/Prizm1 + @ rm -f /mnt/prizm/$< + @ cp $< /mnt/prizm + @ umount /dev/Prizm1 + @- eject /dev/Prizm1 + +.PHONY: all all-fx all-cg clean distclean install-fx install-cg diff --git a/TODO b/TODO new file mode 100644 index 0000000..ebe3322 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +* perf: Try 284x124 at (-60,-28) (all disadvantages) diff --git a/icon-cg-sel.png b/icon-cg-sel.png new file mode 100644 index 0000000000000000000000000000000000000000..f31c66462ba16db886709b65ddba1d865b454c7d GIT binary patch literal 3005 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 literal 0 HcmV?d00001 diff --git a/icon-cg-uns.png b/icon-cg-uns.png new file mode 100644 index 0000000000000000000000000000000000000000..6be38034b3b29adbaa68534c4a04155504d11460 GIT binary patch literal 1426 zcmV;D1#S9?P)Eo z0+tpCwbUZECjLvj&=_Nk#&|HEy>cNY#)JepdFBKpCWH$Y6T^k0CyggeFeJTb{1cTJ zf+$c@Ds3&ixBuSrFlF*FyF2sE?!L17*g4JaoBd|yH^2FPzc;%h{eB;s@@TOd2pUit zP#RE5EKc&)-A?%P(puQJF5g^NJQ;_f&6udfVW{pYh$7c!arrJJV{kih%^8Ll72MR>Q z5b=mz&r<-AM5N`pWyKc|U_>0-R)ey9Ke&8j^@m$)7k~OkqbZke+*|7Of}YB}i1G0e z^Gn5IiurRy_@#m@rt!u6IU@X$LKZ*n-P#Dg{^O1Ylp8ZpR)Os%K#u1 zkyK3~a-_PNqUOuyI_#a@iE>bu;)?kEa{sY&0C4m3kEOa=Q}Xd;t9^AxGuBy&Z;>g#n*Bq%cpFqrsVb!TwG0k3S*2;mU{So;D4XW`4pUGIBWRc;hM5(`4KzR=Ozm1>+MsprclmP zq?M?*PvN}4h5MA2=Z*q&{XjZT!FdN~U;bB+SFAlV6u#8br_kT~U_|J?wz@uL^uWC0 zur_(-CgmL*e~jA`+IdYaeM(*4`&dP20*QCMijw*+xy1OX?~<$TQ&Kgh#P}up6d9C# zZMV&AVs@J_U-uar77vBk>nTGcRS&QZ!Ud*WpVNLx)$s>ifqS; zqlma&!zgBs9Y)kWZyKNY6(9h-F*E-9!r>$DzoY*Uuqn`dM_b6zo;h^}0FIwHK4kOf z^OC0KJl>&H6KHD?6UK8^Ba*xEK$Ct0vNMFefA;WTdr7p!r#G*I|v8)&kuW+qMtg(5=b5?iuf^xRiu zCA7h<+-g+Z*JimA(F+P@_9-U@8SDrTr~SUfrvnJ g^49p229yHjf7{`G<;g~r1poj507*qoM6N<$g8lx|VE_OC literal 0 HcmV?d00001 diff --git a/icon-fx.png b/icon-fx.png new file mode 100644 index 0000000000000000000000000000000000000000..70cab7e4d045f653c412413f73361e70d13323cf GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^azHH1!2~2Z&S+@^Db50q$YP*a2M9AR?&8z{3bL1Y z`ns||;*#Z+($2ml4pP3z)5S5w;`G)~Prd^R94S2i{~Os(5LhH8GL<<~)1WM(rQ?FK zpy2%2`M$reU#yqP;Op&RsF=*zpt?K-t`XMxpc`NqAn{Z=dt z?DzS8J}h0to3o~DX^&ynAK|qZq@#{)`7vkHouwP(JT`xRw6o@L?-GATiv>>1d+xmw z`6*^SCEsnP9+UvOmci52&t;ucLK6V! CO;*Z9Ir46FroZL`@5%HXe)#SUqV%JQzKdLQP77O4>EilYWff;8j1t z_zfOB_ygXYX?I}}8uS2$Nv1Qi`^1BXXe&kEm7v}wF~ H8pfM%Ba5(c literal 0 HcmV?d00001 diff --git a/main.c b/main.c new file mode 100644 index 0000000..1e33c52 --- /dev/null +++ b/main.c @@ -0,0 +1,686 @@ +#include +#include +#include + +#define GINT_NEED_VRAM +#include +#include +#include +#include +#include + + +#ifdef FXCG50 +extern void PrintXY(int x, int y, const char *str, int, int); +extern void Bdisp_PutDisp_DD(void); +extern void Bdisp_AllClr_VRAM(); + +#define color_white 0xffff +#endif + + +/* print() - formatted printing shorthand */ +static void print(int x, int y, const char *format, ...) +{ + char str[45]; + va_list args; + va_start(args, format); + + vsprintf(str + 2, format, args); + + #ifdef FX9860G + dtext(6 * (x - 1) + 1, 7 * (y - 1), str + 2, color_black, color_white); + #endif + + #ifdef FXCG50 + PrintXY(x, y, str, 0, 0); + #endif + + va_end(args); +} + +void print_bin(int x, int y, uint32_t bin, int digits) +{ + char str[33]; + str[digits] = 0; + + while(--digits >= 0) + { + str[digits] = '0' + (bin & 1); + bin >>= 1; + } + + print(x, y, str); +} + +void debug(uint32_t event_code) +{ + print(1, 6, "%8x", event_code); + dupdate(); +} + +void debug_exc(uint32_t event_code) +{ + uint32_t spc; + __asm__("stc spc, %0": "=r"(spc)); + + print(1, 1, "EXCEPTION==%8x==", event_code); + print(1, 2, "SPC=%8x=========", spc); + + if(isSH4()) + { + volatile uint32_t *TEA = (void *)0xff00000c; + print(1, 3, "TEA=%8x=========", *TEA); + } + dupdate(); +} + +#if 0 +volatile int delay_one_ended = 0; +int stop(__attribute__((unused)) void *arg) +{ + delay_one_ended = 1; + return 1; +} +void delay_one(void) +{ + int delay_us = 50000; + static int tid = 1; + +/* if(tid == (isSH3() ? 3 : 7)) tid = (tid + 1) % timer_count(); + + delay_one_ended = 0; + timer_setup(tid, timer_delay(tid,delay_us), timer_default, stop, NULL); + timer_start(tid); + + while(!delay_one_ended) __asm__("sleep"); + timer_free(tid); */ + +// tid = (tid + 1) % timer_count(); +} +void delay(int k) +{ + for(int i = k; i > 0; i--) + { +#ifdef FX9860G + Bdisp_ClearLineVRAM(127, 0, 127, 63); + Bdisp_DrawLineVRAM(127, 0, 127, (63 * i) / k); + Bdisp_PutDisp_DD(); +#endif + delay_one(); + } +} + +#include + +int callback(void *arg) +{ + volatile int *counter = arg; + (*counter)++; + return *counter == 7; +} + +void test_clock(void) +{ + const clock_frequency_t *freq = clock_freq(); + + Bdisp_AllClr_VRAM(); + print(1, 1, "FLL: %8d", freq->FLL); + print(1, 2, "PLL: %8d", freq->PLL); + + print(1, 3, "div1: B%3d I%3d P%3d", + freq->Bphi_div, freq->Iphi_div, freq->Pphi_dev); + + print(1, 5, "Bphi = %10d", freq->Bphi_f); + print(1, 6, "Iphi = %10d", freq->Iphi_f); + print(1, 7, "Pphi = %10d", freq->Pphi_f); + + Bdisp_PutDisp_DD(); + delay(100); + + volatile unsigned int *FRQCRA = (void *)0xa4150000; + volatile unsigned int *FRQCRB = (void *)0xa4150004; + volatile unsigned int *PLLCR = (void *)0xa4150024; + volatile unsigned int *FLLFRQ = (void *)0xa4150050; + + Bdisp_AllClr_VRAM(); + print(1, 1, "%8x", *FRQCRA); + print(1, 2, "%8x", *FRQCRB); + print(1, 3, "%8x", *PLLCR); + print(1, 4, "%8x", *FLLFRQ); + Bdisp_PutDisp_DD(); + delay(100); +} + +void test_timer_simultaneous(void) +{ + volatile int counters[9] = { 0 }; + int count = timer_count(); + Bdisp_AllClr_VRAM(); + + for(int tid = 0; tid < count; tid++) + { + timer_setup(tid, timer_delay(tid, 1000000), timer_default, + callback, (void *)&counters[tid]); + } + + for(int tid = 0; tid < count; tid++) timer_start(tid); + + int limit; + + #ifdef FX9860G + limit = 4000; + #else + limit = 500; + #endif + + for(int i = 0; i < limit; i++) + { + Bdisp_AllClr_VRAM(); + for(int k = 0; k < 9; k++) + print(2 * k + 1, 1, "%1x", counters[k]); + + print(1, 8, "%4d", i); + Bdisp_PutDisp_DD(); + } + + for(int tid = 0; tid < count; tid++) timer_free(tid); +} + +void test_rtc_time(void) +{ + rtc_time_t time; + int limit; + + #ifdef FX9860G + limit = 1500; + #else + limit = 200; + #endif + + for(int i = 0; i < limit; i++) + { + const char *days[7] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", + }; + Bdisp_AllClr_VRAM(); + rtc_get_time(&time); + + print(1, 1, "%2d:%2d:%2d", + time.hours, time.minutes, time.seconds); + print(1, 2, "%2d-%2d-%4d %s", + time.month_day, time.month, time.year, + days[time.week_day]); + + print(1, 8, "%4d", i); + Bdisp_PutDisp_DD(); + } +} + +volatile int test_rtc_int_flag = 0; +int test_rtc_int_callback(UNUSED void *arg) +{ + static int count = 0; + count++; + print(7, 1, "%2d", count); + Bdisp_PutDisp_DD(); + + test_rtc_int_flag = (count == 10); + return test_rtc_int_flag; +} +void test_rtc_int(void) +{ + test_rtc_int_flag = 0; + rtc_start_timer(rtc_1Hz, test_rtc_int_callback, NULL); + + uint32_t vbr = 0x8800df00; + vbr += 0x600; + vbr += 0x20; + vbr += 0xaa0 - 0x400; + vbr += 20; + + Bdisp_AllClr_VRAM(); + print(1, 1, "count="); + Bdisp_PutDisp_DD(); + while(!test_rtc_int_flag) __asm__("sleep"); + delay(100); + + /* Not needed since the callback stops the timer + rtc_stop_timer(); */ +} + +/* Count how many interrupts I can process in a second */ +volatile int test_timer_stress_counter = 0; +volatile int test_timer_stress_done = 0; +int test_timer_stress_callback(void *arg) +{ + volatile int *counter = arg; + (*counter)++; + return 0; +} +int test_timer_stress_stop(UNUSED void *arg) +{ + timer_pause(0); + timer_free(0); + + test_timer_stress_done = 1; + return 1; +} +int test_timer_stress_start(UNUSED void *arg) +{ + rtc_start_timer(rtc_1Hz, test_timer_stress_stop, NULL); + timer_start(0); + return 0; +} +void test_timer_stress(void) +{ + int length = 0; + gint_intlevel(isSH3() ? 3 : 40, 15); + + Bdisp_AllClr_VRAM(); + print(1, 1, "Testing..."); + Bdisp_PutDisp_DD(); + + timer_setup(0, timer_delay(0, length), timer_default, + test_timer_stress_callback, (void*)&test_timer_stress_counter); + rtc_start_timer(rtc_1Hz, test_timer_stress_start, NULL); + + do __asm__("sleep"); + while(!test_timer_stress_done); + + Bdisp_AllClr_VRAM(); + print(1, 1, "Test finished!"); + print(1, 2, "length = %8d ms", length); + print(1, 3, "Processed interrupts:"); + print(1, 4, "%7d", test_timer_stress_counter); + Bdisp_PutDisp_DD(); + + gint_intlevel(isSH3() ? 3 : 40, 5); + delay(60); +} +#endif + +#define TEST_TIMER_FREQ_LIMIT 64 +#define TEST_TIMER_FREQ_RTC RTC_16Hz +#define TEST_TIMER_FREQ_TIMER 62500 +#define TEST_TIMER_FREQ_TID 7 + +#include + +int test_timer_freq_callback(volatile void *arg) +{ + volatile int *counter = arg; + (*counter)++; + return (*counter == TEST_TIMER_FREQ_LIMIT); +} +int test_timer_freq_start(volatile void *arg) +{ + rtc_start_timer(TEST_TIMER_FREQ_RTC, test_timer_freq_callback, arg); + timer_start(TEST_TIMER_FREQ_TID); + return 0; +} +void test_timer_freq(void) +{ + volatile int tmu = 0, rtc = 0; + int tid = TEST_TIMER_FREQ_TID; + + timer_setup(tid, timer_delay(tid, TEST_TIMER_FREQ_TIMER), + timer_default, test_timer_freq_callback, &tmu); + rtc_start_timer(TEST_TIMER_FREQ_RTC, test_timer_freq_start, &rtc); + + while(rtc < TEST_TIMER_FREQ_LIMIT) + { + dclear(color_white); + print(1, 1, "TMU %4x", tmu); + print(1, 2, "RTC %4x", rtc); + + dupdate(); + } +} + +void display_keys(volatile uint8_t *keys) +{ + for(int r = 0; r < 8; r++) print_bin(1, r + 1, keys[r ^ 1], 8); + for(int r = 0; r < 4; r++) print_bin(10, r + 1, keys[(r + 8) ^ 1], 8); +} + +void keysc_userland(void) +{ + volatile uint16_t *KEYSC = (void *)0xa44b0000; + uint16_t buffer[6]; + + for(int counter = 0; counter < 4000; counter++) + { + for(int i = 0; i < 6; i++) buffer[i] = KEYSC[i]; + if(buffer[3] & 0x0800) break; + dclear(color_white); + display_keys((volatile uint8_t *)buffer); + dupdate(); + } +} + +int keysc_callback(volatile void *arg) +{ + volatile uint16_t *buf = arg; + volatile uint16_t *KEYSC = (void *)0xa44b0000; + + for(int i = 0; i < 6; i++) buf[i] = KEYSC[i]; + return 0; +} + +void keysc_timer(void) +{ + volatile uint16_t buffer[6] = { 0 }; + int tid = 3; + + /* 32 gives 1024 Hz */ + /* 2048 gives 16 Hz */ +#define DELAY 256 + + timer_setup(tid, DELAY, 0, keysc_callback, &buffer); + timer_start(tid); + + dclear(color_white); + +#ifdef FX9860G +# define LIMIT 4000 +#else +# define LIMIT 500 +#endif + + for(int counter = 0; counter < LIMIT; counter++) + { + display_keys((volatile uint8_t *)buffer); + print(18, 8, "%4d", counter); + dupdate(); + } + + timer_stop(tid); +} + +void test_kbd(void) +{ + key_event_t ev; + key_event_t last = { .type = KEYEV_NONE }; + const char *names[4] = { "NONE", "DOWN", "UP ", "HOLD" }; + + extern int time; + int pressed[12][8]; + + for(int i = 0; i < 12; i++) for(int j = 0; j < 8; j++) pressed[i][j]=0; + + dclear(color_white); + + while(1) + { + while((ev = pollevent()).type != KEYEV_NONE) + { + last = ev; + if(ev.type == KEYEV_DOWN && ev.key == KEY_EXIT) return; + + int row = ev.key >> 4; + int col = ev.key & 0xf; + + if(ev.type == KEYEV_DOWN) pressed[row][col] = 1; + if(ev.type == KEYEV_UP) pressed[row][col] = 0; + } + + print(1, 4, "[%4d]", time); + print(1, 5, "%2x %s", last.key, names[last.type]); + + for(int i = 0; i < 8; i++) + { + int x = (i < 8) ? 13 : 2; + int y = (i < 8) ? 8 - i : 12 - i; + + for(int j = 0; j < 8; j++) +// Bdisp_SetPoint_VRAM(80 + 2 * j, 2 + 2 * i, +// pressed[i][j]); + print(x + j, y, pressed[i][j] ? "#" : "-"); + } + + extern volatile uint8_t state[12]; + print(1,1,"%x %x %x %x",state[0],state[1],state[2],state[3]); + print(1,2,"%x %x %x %x",state[4],state[5],state[6],state[7]); + print(1,3,"%x %x %x %x",state[8],state[9],state[10],state[11]); + dupdate(); + } +} + +/* tmu_t - a single timer from a standard timer unit */ +typedef volatile struct +{ + uint32_t TCOR; /* Constant register */ + uint32_t TCNT; /* Counter register, counts down */ + + word_union(TCR, + uint16_t :7; + uint16_t UNF :1; /* Underflow flag */ + uint16_t :2; + uint16_t UNIE :1; /* Underflow interrupt enable */ + uint16_t CKEG :2; /* Input clock edge */ + uint16_t TPSC :3; /* Timer prescaler (input clock) */ + ); + +} GPACKED(4) tmu_t; + +/* tmu_extra_t - extra timers on sh7337, sh7355 and sh7305 */ +typedef volatile struct +{ + uint8_t TSTR; /* Only bit 0 is used */ + pad(3); + + uint32_t TCOR; /* Constant register */ + uint32_t TCNT; /* Counter register */ + + byte_union(TCR, + uint8_t :6; + uint8_t UNF :1; /* Underflow flag */ + uint8_t UNIE :1; /* Underflow interrupt enable */ + ); + +} GPACKED(4) tmu_extra_t; + +/* This is the description of the structure on SH4. SH3-based fx9860g models, + which are already very rare, will adapt the values in init functions */ +tmu_t *std[3] = { + (void *)0xa4490008, + (void *)0xa4490014, + (void *)0xa4490020, +}; +tmu_extra_t *ext[6] = { + (void *)0xa44d0030, + (void *)0xa44d0050, + (void *)0xa44d0070, + (void *)0xa44d0090, + (void *)0xa44d00b0, + (void *)0xa44d00d0, +}; +tmu_t *std3[3] = { + (void *)0xfffffe94, + (void *)0xfffffea0, + (void *)0xfffffeac, +}; +tmu_extra_t *ext3[1] = { + (void *)0xa44c0030, +}; + +void initial_timer_status(void) +{ + dclear(color_white); + print(1, 1, "STR"); + print(1, 2, "TCR"); + print(1, 3, "COR"); + print(1, 4, "CNT"); + + print(1, 5, "TCR"); + print(1, 6, "COR"); + print(1, 7, "CNT"); + + for(int i = 0; i < 3; i++) + { + tmu_t *t = (isSH3() ? std3[i] : std[i]); + print(5 + 5*i, 5, "%4x", t->TCR.word); + print(5 + 5*i, 6, (t->TCOR == 0xffffffff) ? "ffff" : "????"); + print(5 + 5*i, 7, (t->TCNT == 0xffffffff) ? "ffff" : "????"); + } + + for(int i = 0; i < (isSH3() ? 1 : 6); i++) + { + tmu_extra_t *t = (isSH3() ? ext3[i] : ext[i]); + print(5 + 3*i, 1, "%2x", t->TSTR); + print(5 + 3*i, 2, "%2x", t->TCR.byte); + print(5 + 3*i, 3, (t->TCOR == 0xffffffff) ? "ff" : "??"); + print(5 + 3*i, 4, (t->TCNT == 0xffffffff) ? "ff" : "??"); + } + + dupdate(); +} + +#ifdef FX9860G +void fx_frame1(void) +{ + dclear(color_white); + for(int x = 0; x < 256; x += 4) vram[x] = vram[x + 1] = 0xffffffff; + for(int r = 0; r <= 8; r += 2) + { + for(int x = r; x < 64 - r; x++) + { + dpixel(x, r, color_reverse); + dpixel(x, 127 - r, color_reverse); + } + for(int y = r + 1; y < 128 - r; y++) + { + dpixel(r, y, color_reverse); + dpixel(63 - r, y, color_reverse); + } + } + dupdate(); +} +void fx_frame2(void) +{ + dclear(color_white); + for(int x = 20; x <= 88; x += 68) + for(int y = 10; y <= 44; y += 34) + { +// drect(x, y, 20, 10, color_black); + } + + dline(64, 32, 84, 32, color_reverse); + dline(64, 32, 78, 18, color_reverse); + dline(64, 32, 64, 12, color_reverse); + dline(64, 32, 50, 18, color_reverse); + dline(64, 32, 44, 32, color_reverse); + dline(64, 32, 44, 46, color_reverse); + dline(64, 32, 64, 52, color_reverse); + dline(64, 32, 78, 46, color_reverse); +} +#endif + +typedef void asm_text_t(uint32_t *v1, uint32_t *v2, uint32_t *op, int height); +extern asm_text_t *topti_asm_text[8]; + +int main(GUNUSED int isappli, GUNUSED int optnum) +{ + getkey(); +#ifdef FX9860G + + extern image_t pattern; + extern image_t pattern2; + +/* image_t *img = &pattern; + + uint32_t *data = (void *)&img->data; + + for(int i = 0; i < 32; i++) vram[4 * i] = data[i]; + dupdate(); + getkey(); + + fx_frame1(); + getkey(); + fx_frame2(); + getkey(); */ + + int x = 0, y = 0, k = 0, w, h; + + while(k != KEY_EXIT) + { + dclear(color_white); +// bopti_render_clip(x, y, &pattern2, 0, 0, 48, 16); + dtext(x, y, "Hello, World!", color_white, color_black); + dsize("Hello, World!", NULL, &w, &h); + drect(x, y, x + w - 1, y + h - 1, color_reverse); + dupdate(); + + k = getkey().key; + if(k == KEY_LEFT /* && x > 2 */) x-=3; + if(k == KEY_RIGHT /* && x < 92 */) x+=3; + if(k == KEY_UP /* && y > 2 */) y-=3; + if(k == KEY_DOWN /* && y < 30 */) y+=3; + } + +#endif + +/* #ifdef FXCG50 + initial_timer_status(); + Bdisp_PutDisp_DD(); + getkey(); +#endif */ + +#ifdef FXCG50 + #define rgb(r, g, b) ((r << 11) | (g << 5) | b) + + dclear(0xf800); + for(int i = 1; i <= 10; i++) + { + drect(i, i, 395 - i, 223 - i, (i & 1) ? 0xffff: 0xf800); + } + + int cx = 100, cy = 100; + int r = 30; + + drect(cx-r, cy-r, cx+r, cy+r, 0xffff); + for(int k = -r; k <= r; k += 10) + { + dline(cx, cy, cx+k, cy-r, 0x0000); + dline(cx, cy, cx+k, cy+r, 0x0000); + + dline(cx, cy, cx-r, cy+k, 0x0000); + dline(cx, cy, cx+r, cy+k, 0x0000); + } + + for(int y = 0; y < 20; y++) + for(int x = 0; x < 20; x++) + { + dpixel(180+x, 30+y, ((x^y) & 1) + ? rgb(10, 21, 10) + : rgb(21, 43, 21)); + } + + dupdate(); + getkey(); + + for(int y = 0; y < 224; y++) + for(int x = 0; x < 396; x++) + { + int v = y >> 3; + int h = x >> 3; + vram[396 * y + x] = 0x3eb7 ^ ((v << 11) + (h << 5) + v); + } + + volatile int flag = 0; + int iterations = 0; + timer_setup(0, timer_delay(0, 1000 * 1000), 0, timer_timeout, &flag); + timer_start(0); + + while(!flag) r61524_display(vram, 0, 224), iterations++; + + Bdisp_AllClr_VRAM(); + print(1, 1, "%3d FPS", iterations); + Bdisp_PutDisp_DD(); + getkey(); +#endif + + return 0; +} diff --git a/resources/pattern.png b/resources/pattern.png new file mode 100644 index 0000000000000000000000000000000000000000..24c799fc1403a1c542edde95c17a00cbc704a751 GIT binary patch literal 1444 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 + +/* Drawing functions: + * ... + Keyboard tests: + * ... + Timer tests: + * Do more in-depth things than previous application + * Stress testing for number of interrupts + * ... + Boot log: + * Displays boot log on full screen + * F1 for details (get live explanation and detect problems) + * F2 to save to file */ + +void locate(int x, int y, const char *str) +{ +#ifdef FX9860G + dtext(6*(x-1), 7*(y-1), str); +#else + PrintXY(x, y, str - 2, 0, 0); +#endif +}