signori scusatemi , sono riuscito a risolvere il "grosso problema" che citerò più sotto.
Come? ricordandomi che il tizio da cui ho preso l'idea aveva scritto "static inline", mentre io pensai qualcosa come " che significa static? è C, non C++, io so che in java (e dunque presumo in C++) static significa che non dipende da un oggetto, ma qui non so cosa faccia, dunque non lo metterò, ecco." invece ora ho pensato "ma se il tizio l'ha messo, ci sarà un motivo? ok non so cosa vuol dire, ma proviamo giusto per curiosità"... e vaa!
unici 2 problemi:
- peccato che però non "inlinea" comunque la funzione
- cosa significa "static"?
per chi è curioso di sapere come andava a finire prima di "questa notizia bomba" (alla top gear), lascio sotto il post originale.
(ma si può fare uno spoiler?)
all'inizio avevo detto che uso questo comando (qui ho semplificato le parti inutili):
"D:\devkitPro\devkitARM\bin\arm-none-eabi-gcc.exe" -Wall -mthumb -mthumb-interwork -S nomedelfile.c
uso il devkitpro per sviluppare sul gameboy advance.
poi, dopo aver ottenuto il file s, lo assemblo (il comando dell'assemblatore l'ho copiato da internet):
as -a -mthumb -mthumb-interwork "%src%"
objcopy --verbose -O binary a.out "%dest%"
e lo innesto in un gioco già compilato (lo so che è un comportamento demoniaco, ma mi serve).
prendendo un semplice file C tipo questo:
int chiamata (char, short);
void prova ()
{
int a = chiamata (0xB, 10);
}
int chiamata(char a, short b)
{
return ((short) a + b);
}
senza ottimizzazioni (perchè se no mi segava questo esempio con la variabile non utilizzata) si genera una cosa del genere:
.syntax unified
.cpu arm7tdmi
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 1
.eabi_attribute 30, 6
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.thumb
.syntax unified
.file "provablpiero.c"
.text
.align 2
.global prova
.code 16
.thumb_func
.type prova, %function
prova:
push {r7, lr}
sub sp, sp, #8
add r7, sp, #0
movs r1, #10
movs r0, #11
bl chiamata
movs r3, r0
str r3, [r7, #4]
nop
mov sp, r7
add sp, sp, #8
@ sp needed
pop {r7}
pop {r0}
bx r0
.size prova, .-prova
.align 2
.global chiamata
.code 16
.thumb_func
.type chiamata, %function
chiamata:
push {r7, lr}
sub sp, sp, #8
add r7, sp, #0
movs r2, r0
adds r3, r7, #7
strb r2, [r3]
adds r3, r7, #4
adds r2, r1, #0
strh r2, [r3]
adds r3, r7, #7
ldrb r2, [r3]
adds r3, r7, #4
movs r1, #0
ldrsh r3, [r3, r1]
adds r3, r2, r3
movs r0, r3
mov sp, r7
add sp, sp, #8
@ sp needed
pop {r7}
pop {r1}
bx r1
.size chiamata, .-chiamata
.ident "GCC: (devkitARM release 45) 5.3.0"
tralasciando tutte le cose inutili tipo eabi attribute che manco so cosa sia e il walzer dello stack pointer, si vede chiaramente che chiama con un BL la funzione identificata con l'etichetta.
tuttavia l'assemblatore ha qualche problema:
postimg.org/image/pony0yz6p/
la riga evidenziata salta a sé stessa.
ma in realtà non è questo il mio vero problema, in quanto una passata con un semplice programma che legge l'output e lo corregge mettendo il punto all'inizio dell'etichetta basta a far funzionare il tutto.
Vorrei tuttavia approfittare dell'occasione per chiedervi un'altra cosa, ma sempre riguardante questi argomenti.
Forse sbaglio qualcosa io, ma procediamo con ordine. vi spiego tutto il setup.
voglio inserire nel gioco GBA delle mie funzioni in C, e avevo pensato di facilitare lo sviluppo mettendole tutte una di seguito all'altra, e avere una specie di main richiamato dal gioco che legge in una locazione di ram (indirizzo 0x02......) il numero della funzione da richiamare. In questo modo avrei potuto aggiornare facilmente le funzioni nel caso ci fossero stati problemi o per aggiungere funzionalità, senza stare troppo a trafficare con i files.
il trucco sta nel mettere una parola chiave tipo 0xCAFEBABE (ho usato uno stupido "start of frame" come parola chiave, in onore del TCP
), che il mio programma java avrebbe rilevato nel file binario, e grazie a questo aggiustato un altro piccolo file ad offset fisso che ha solo il compito di "linkare" (da branch and link) al finto main che seleziona la funzione da avviare.
Infine il programma java assembla nella ROM questa piccola routine insieme al file binario compilato.
Tuttavia ho alcuni problemi, di diversa entità. Quello più grave, per cui chiedo a voi una mano, è che se metto "troppe" funzioni nel sorgente C (al momento circa 16), quando assemblo il tutto e faccio il debug con l'emulatore, vedo che quando bisogna fare un branch and link il program counter "va per i campi", termine simpatico che ho inventato per dire che va ad un offset dove non c'è assolutamente alcuna funzione. In quel punto capita sempre di trovare parecchie istruzioni di LSR/LSL (logical shift), ed è molto curioso. potrebbe trattarsi di padding, ma ne dubito. E ovviamente il gioco crasha. Questo è un comportamento molto misterioso, perchè ho ricontrollato più volte il sorgente asm. Forse ho sbagliato qualche parametro dei vari compilatori/assemblatori? Non vorrei aver sbagliato qualcosa nel programmino java, anche se mi sembra strano, perchè fino a 10-12 funzioni va perfettamente! Adesso mentre sto scrivendo sono andato a controllare: ho eseguito il passaggio manualmente (prima mi affidavo ai tools di code blocks e ai batch), assemblando il file .S. e in effetti è sbagliato: non corrisponde.
Ho pensato sbagliassi qualcosa nella funzione, così ne ho creata una completamente diversa, ma ancora il problema si ripresenta (branch and link dove non v'è niente).
Ancora, ho provato a mettere il main prima di tutte le implementazioni delle funzioni, e dopo le dichiarazioni, ma senza successo.
Vi segnalo inoltre che aggiungere le funzioni non causa problema di esecuzione, ma soltanto chiamarle.
Cosa sbaglio? ve ne sarei tanto grato. (scusate la figura nabba e alcune probabili oscenità nel codice)
va beh, senza ulteriori indugi vi passo tutto il materiale.
piccola routine collocata ad un offset fisso nella ROM, verrà chiamata dal gioco e caricherà le mie funzioni:
.THUMB
.ALIGN 2
PUSH {r0-r7, lr}
ldr r1, .base
BL LINKER
POP {r0-r7, pc}
LINKER:
BX R1
.align 2, 0x00
.base:
.word 0xAABBCCDD
la word verrà cambiata dal programma java che mette insieme tutto.
programmino in java, nel caso servisse (in generale non dovrebbe servire, lo metto lo stesso però non deridetemi, è stato programmato molto "alla buona", se non rispetta certi canoni stilistici, skippate al paragrafo successivo per non subire danni agli occhi
package it.bonnox.asmdeployer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import it.bonnox.myLibPers.basicBytesLibrary.CoreLibrary;
import it.bonnox.myLibPers.basicBytesLibrary.Pointer;
import it.bonnox.myLibPers.utils.*;
public class MainDeployer
{
private static final int SCOSTAMENTO_ALIGN = 64;
private static final int DIMENSIONE_AREA_COMPILAZIONE = 6 * 1024 * 1024;
private static final int ARG_OFFSETINSERIMENTO = 2;
private static final int ARG_PERCORSOCOMPILATO = 1;
private static final int ARG_PERCORSOROM = 0;
private static byte[] LINKERROUTINEBINARY = { (byte) 0xFF, (byte) 0xB5, (byte) 0x02, (byte) 0x49, (byte) 0x00, (byte) 0xF0, (byte) 0x01, (byte) 0xF8, (byte) 0xFF, (byte) 0xBD, (byte) 0x08, (byte) 0x47, (byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA };
private static final int ARG_DEFINE = 3;
private static final boolean DEBUG = false;
@SuppressWarnings ("unused")
public static void main(String[] args) throws IOException
{
System.out.println("\ndeploying...");
if (DEBUG) System.err.println(" *** DEBUG ***");
if (args.length != ARG_DEFINE && !DEBUG)
{
System.err.println("WRONG NUMBER OF PARAMERERS\n" + "usage:\n" + "rom\n" + "filebin\n" + "offset\n");
System.exit(-1);
}
String percorsoROM;
String percorsoCompilato;
int offsetInserimento;
if (DEBUG)
{
percorsoROM = "D:\GXX-XDS\C Environment Deployment\out\test.gba";
percorsoCompilato = "D:\GXX-XDS\C Environment Deployment\middle\test.s.bin";
offsetInserimento = 0x1c00000;
}
else
{
percorsoROM = args[ARG_PERCORSOROM];
percorsoCompilato = args[ARG_PERCORSOCOMPILATO];
offsetInserimento = Integer.parseInt(args[ARG_OFFSETINSERIMENTO], 16);
}
byte[] bytesROM = Files.readAllBytes(Paths.get(new File(percorsoROM).toURI()));
System.out.println("opening compiled...");
byte[] bytesCompilato = Files.readAllBytes(Paths.get(new File(percorsoCompilato).toURI()));
int indirizzoMain = getMainCompilato(bytesCompilato, offsetInserimento);
if (indirizzoMain < 0) System.exit(indirizzoMain);
sostituisciLinker(LINKERROUTINEBINARY, indirizzoMain);
// unisce le parti
byte[] inserimento = new byte[DIMENSIONE_AREA_COMPILAZIONE];
// copia il linker
for (int i = 0; i < LINKERROUTINEBINARY.length; i++)
{
inserimento[i] = LINKERROUTINEBINARY[i];
}
// copia la compilazione
for (int i = LINKERROUTINEBINARY.length; i < bytesCompilato.length; i++)
{
inserimento[i] = bytesCompilato[i];
}
noppa(inserimento, LINKERROUTINEBINARY.length, bytesCompilato.length);
scriviROM(bytesROM, percorsoROM, offsetInserimento, inserimento);
}
private static void noppa(byte[] inserimento, int length, int length2)
{
for (int i = length + length2; i < inserimento.length; i += 2)
{
if (i == inserimento.length)
{
// se i è uguale all ultimo , vuol dire che e dispari
// (?)
inserimento[i] = (byte) 0xC0;
}
else
{
inserimento[i] = (byte) 0xC0;
inserimento[i + 1] = (byte) 0x46;
}
}
}
private static void sostituisciLinker(byte[] lINKERROUTINEBINARY2, int indirizzo)
{
Pointer nuovo = new Pointer(indirizzo);
it.bonnox.myLibPers.basicBytesLibrary.CoreLibrary.writeBytes(lINKERROUTINEBINARY2, lINKERROUTINEBINARY2.length - 4, nuovo.getBinaryGBA());
}
private static int getMainCompilato(byte[] bytesCompilato, int offsetinserimento)
{
int ritorno = -1;
for (int i = 0; i < bytesCompilato.length; i += SCOSTAMENTO_ALIGN)
{
if (DEBUG)
{
}
if (bytesCompilato[i] == 'S') if (bytesCompilato[i + 1] == 'T') if (bytesCompilato[i + 2] == 'A') if (bytesCompilato[i + 3] == 'R') if (bytesCompilato[i + 4] == 'T') if (bytesCompilato[i + 5] == (byte) 0x20) if (bytesCompilato[i + 6] == 'O') if (bytesCompilato[i + 7] == 'F') if (bytesCompilato[i + 8] == ' ') if (bytesCompilato[i + 9] == 'F') if (bytesCompilato[i + 10] == 'R') if (bytesCompilato[i + 11] == 'A') if (bytesCompilato[i + 12] == 'M') if (bytesCompilato[i + 13] == 'E') if (bytesCompilato[i + 14] == ' ') if (bytesCompilato[i + 15] == ' ')
{
ritorno = i;
}
}
return ritorno + LINKERROUTINEBINARY.length + offsetinserimento;
}
private static void scriviROM(byte[] ROMfile, String percorso, int offsetInserimento, byte[] nuovi) throws FileNotFoundException, IOException
{
System.out.println("finalizing...");
CoreLibrary.writeBytes(ROMfile, offsetInserimento, nuovi);
Misc.salvaFile(new File(percorso), ROMfile);
System.out.println("successfully deployed.");
}
}
ecco il codice sorgente. cerco di spiegare il tutto, ma avviso che è un'adattamento di un mio appunto.
quando dirò "variabile 0x800D" significa essenzialmente "indirizzo di memoria inutilizzato".
il file "test.c" è quello che unisce tutto: contiene sia la libreria che le funzioni. il metodo main legge la variabile 0x800D ed esegue la routine corrispondente!
poi quando le singole routine raggiungeranno una certa complessità verranno pure loro separate nel loro file C e incluse. So che per certa gente seria è impensabile, abominevole, demoniaco, #includere i file C e ricompilare il mondo. è naive ma funziona; non so i makefiles, e poi la ROM è una struttura parecchio statica: bisogna cercare di prevedere cosa uscirà pena errori orribili! Ecco cosa mi ha portato a questa scelta.
il file header è unico, ho scelto così perchè tanto la libreria se uno la vuole se la include tutta, non è che risparmi chissà chi se non vuole qualche modulo; prima ogni pezzetto in C aveva il suo header, ben schermato con l'#ifdef, per carità, ma poi ovviamente è successo il fattaccio (prima o poi sarebbe dovuto accadere, era una questione di tempo) :p sicuramente colpa di qualche stupido punto e virgola, mi ha mandato a
lucciole tutti gli include.... così poi li ho uniti! ahaha ^^
ogni pezzetto svolge precisi compiti:
- math è nato come utilità per fixed floating point (anche se non ne troverai traccia perchè devo ancora studiarci su :p ), poi ho deciso di mettere anche i div, poi ne ho tolto uno, poi li ho uniti, boh i div sono un casino.
- bios contiene principalmente asm per usare il bios del GBA. i div sono problematici, non so come farlo ritornare, eccetera. poi ne ho messi ancora pochi altri (anche sotto forma di #define se non prendono argomenti, così sono più leggeri
). ovviamente bisognerà metterli quasi tutti, a parte il suono e gli affini che non interessano a nessuno.
- util contiene... utilità. non saprei definirlo in altro modo. occhio che ha il vizio di ritornare le cose nella variabile 800D (e byte seguenti)
- video dovrebbe contenere robe tipo inizializza i modi grafici, mostra immagini, copia i tils.... ma per ora contiene solo un orrenda funzione con un casino di parametri short che quadruplicano il listato asm a forza di shift per conversioni forzate... e non va bene.
[...]
da qui in poi, se aggiungo una funzione, succede il patatrak, ovvero non la chiama e va in posti sperduti del binario.
al momento c'è il file "text", che contiene una specie di sistema di testo. è ancora tutto in fase embrionale, c'è un po' di disordine e mancano funzionalità (tipo c'è il put carattere ma non il put stringa, e nemmeno la gestione della console).
la mia idea era di ricreare la libreria tipo tonc o libgba, non essendo riuscito a farle funzionare.
tanto comunque saranno pochi altri i metodi che dovrò inserire.
grazie ancora.
non fate caso a scritte strane
file test.c:
#include "libonnox.h"
#include "libonnox/bios.c"
#include "libonnox/math.c"
#include "libonnox/util.c"
#include "libonnox/video.c"
#include "libonnox/text.c"
/* TODO
problemi:
- se metto troppe funzioni, l'as va per campi.
- fascia nera a sx del gba
problemi risolti:
----------
problemi boh:
- gcc ottimizz sbaglia a tradurre blockfill in versione c. mentre in versione asm da qualche tempo mi fa un b here che non riesco a evitare. vedere tale file x dettagli
mettendo la flag da -O2 a -O1, il C funge :)
non e' vero, ora non va piu, devo toglierle del tutto :c
*/
void metodo()
{
u16 tmp= DISPCNT;
//util_blockfill(0x04000000, 256, 0x0);
*(unsigned int*)0x04000000 = 0x0403;
//util_memAlloc32(0x8);
/*
OFFSET_AS_POINTER8(0x4000021)=(u8)1;
OFFSET_AS_POINTER8(0x4000027)=(u8)1;
OFFSET_AS_POINTER8(0x4000031)=(u8)1;
OFFSET_AS_POINTER8(0x4000037)=(u8)1;
OFFSET_AS_POINTER8(0x4000082)=(u8)0xe;
OFFSET_AS_POINTER8(0x4000089)=(u8)0x2;
*/
util_blockFill(0x06000000, 5600, 0x7fff7fff);
/*u32 color=RGB16(9, 1, 2);
color=color<<16;
color+=RGB16(5, 5, 5);
util_blockFill(0x06000000+9600*4, 9600, color);//BREAKPOINT;*/
//util_blockFill(0x04000010, 4, 0x0);
//draw_line (1, 50, 0x3456);
text_putc16bpp ('a', 30, 4, 0x3333);
//DISPCNT=tmp;
}
void linker(u16 nf)
{
switch (nf)
{
case 0:
metodo();
break;
}
}
NEW_FUNC;
void hackMain()
{
linker(OFFSET_AS_POINTER16(var_0x800D));
}
libonnox.h
/**
---------------
USEFUL
---------------
*/
#define ASM_CMT(str) asm ("@; " str)
#define CALL(str) asm("bl ." str )
#define NEW_FUNC \
ASM_CMT("-----------------");\
ASM_CMT("-----------------");\
asm (".align 6, 0x00");\
asm (".ascii \"START OF FRAME \" " ) ; \
asm (".align 4, 0x00");\
ASM_CMT("-----------------");\
ASM_CMT("-----------------")
#define MY_FUNC \
ASM_CMT("-----------------");\
ASM_CMT("-----------------");\
asm (".align 8, 0x00");\
asm (".ascii \"MAIN\" " ) ; \
asm (".align 4, 0x00");\
ASM_CMT("-----------------");\
ASM_CMT("-----------------")
#define BREAKPOINT asm (".align 1");\
asm (".byte 0xfe, 0x0");\
asm (".byte 0xe7");\
asm (".align 1, 0x0")
/* asm (".align 1");\
asm (".byte 0xfe");\
asm (".byte 0xde");\
asm (".align 1")
*/
#define OFFSET_AS_POINTER8(num) (*(u8*)num)
#define OFFSET_AS_POINTER16(num) (*(u16*)num)
#define OFFSET_AS_POINTER32(num) (*(u32*)num)
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#define ASM_800D_R4 \
asm ("mov r4, #2");\
asm (" lsl r4, #0x8");\
asm ("add r4, r4, #2");\
asm ("lsl r4, #0x4");\
asm ("add r4, r4, #14");\
asm ("lsl r4, #0x4");\
asm ("add r4, r4, #8");\
asm ("lsl r4, #0x4");\
asm ("add r4, r4, #13");\
asm ("lsl r4, #0x4");\
asm ("add r4, r4, #12")
/**
---------------
BOOL
---------------
*/
typedef u32 boolean;
#define TRUE 1
#define FALSE 0
/**
---------------
BIOS
---------------
*/
#define bios_vBlankIntrWait() asm ("swi 0x5")
#define bios_halt() asm ("swi 0x2")
#define bios_intrWait() asm ("swi 0x4")
#define bios_div_single_DIV 1
#define bios_div_single_MOD 2
void bios_div_single (u32 num, u32 den, u32 func);
void bios_div_multi (u32 num, u32 den, u32* alloc);
/**
---------------
VIDEO
---------------
*/
#define RGB16(r,g,b) (r+(g<<5)+(b<<10))
#define MAX_COLOR_VALUE 31 // i colori sono 0-bbbbb-ggggg-rrrrr
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 160
#define DISPCNT_BGMODE_PROPERTY 0
#define DISPCNT_FRAME_PROPERTY 3
#define DISPCNT_H_BLANK_PROPERTY 5
#define DISPCNT_OBJMAP_PROPERTY 6
#define DISPCNT_FORCEDBLANK_PROPERTY 7
#define DISPCNT_BG0_PROPERTY 8
#define DISPCNT_BG1_PROPERTY 9
#define DISPCNT_BG2_PROPERTY 10
#define DISPCNT_BG3_PROPERTY 11
#define DISPCNT_OBJ_PROPERTY 12
#define DISPCNT_WIN0_PROPERTY 13
#define DISPCNT_WIN1_PROPERTY 14
#define DISPCNT_WINOBJ_PROPERTY 15
#define CLR_BLACK 0x0000
#define CLR_RED 0x001F
#define CLR_LIME 0x03E0
#define CLR_YELLOW 0x03FF
#define CLR_BLUE 0x7C00
#define CLR_MAG 0x7C1F
#define CLR_CYAN 0x7FE0
#define CLR_WHITE 0x7FFF
typedef u16 T_COLOR;
//void initM3();
void video_initDispCntGlobal(u8 bgMode, boolean frame, boolean hBlank, boolean objMapping, boolean forceBlank, boolean bg0, boolean bg1, boolean bg2, boolean bg3, boolean obj, boolean win0, boolean win1, boolean winObj);
void video_setDispCntProperties(u8 property, u8 bgMode, boolean flag);
u16 video_createDispCnt(u8 bgMode, boolean frame, boolean hBlank, boolean objMapping, boolean forceBlank, boolean bg0, boolean bg1, boolean bg2, boolean bg3, boolean obj, boolean win0, boolean win1, boolean winObj);
T_COLOR video_alphaBlend(T_COLOR source, T_COLOR newcol, u8 coef);
void video_plotPixelM3(u8 x, u8 y, T_COLOR color, boolean transp);
inline void video_plotPixelM3inline (int x, int y, T_COLOR clr);
inline int video_getR(T_COLOR clr);
inline int video_getG(T_COLOR clr);
inline int video_getB(T_COLOR clr);
/**
---------------
UTIL
---------------
*/
#define var_0x800D 0x0202E8DC
void util_memcpy32(u32 dst, u32 src, u32 wdcount);
void util_blockFill(u32 dest, u32 lung, u32 filler);
void util_memAlloc32(u32 lung);
void util_memFree32(u32 offs);
/**
---------------
TEXT
---------------
*/
void text_putc16bpp (u8 chr, u8 x, u8 y, T_COLOR clr);
/**
---------------
MATH
---------------
*/
u32* math_div_multiple(u32 n, u32 d, boolean allocNeed, u32* offs);
/**
---------------
IOREG
---------------
*/
#define DEFINEREG16(num) (*(volatile u16*) num)
#define DEFINEREG32(num) (*(volatile u32*) num)
#define BASE_REG 0x4000000
#define DISPCNT DEFINEREG16(0x4000000)
#define DISPSTAT DEFINEREG16(0x4000004)
#define VCOUNT DEFINEREG16(0x4000006)
#define BG0CNT DEFINEREG16(0x4000008)
#define BG1CNT DEFINEREG16(0x400000A)
#define BG2CNT DEFINEREG16(0x400000C)
#define BG3CNT DEFINEREG16(0x400000E)
#define BG0HOFS DEFINEREG16(0x4000010)
#define BG0VOFS DEFINEREG16(0x4000012)
#define BG1HOFS DEFINEREG16(0x4000014)
#define BG1VOFS DEFINEREG16(0x4000016)
#define BG2HOFS DEFINEREG16(0x4000018)
#define BG2VOFS DEFINEREG16(0x400001A)
#define BG3HOFS DEFINEREG16(0x400001C)
#define BG3VOFS DEFINEREG16(0x400001E)
#define BG2PA DEFINEREG16(0x4000020)
#define BG2PB DEFINEREG16(0x4000022)
#define BG2PC DEFINEREG16(0x4000024)
#define BG2PD DEFINEREG16(0x4000026)
#define BG2X DEFINEREG32(0x4000028)
#define BG2Y DEFINEREG32(0x400002C)
#define BG3PA DEFINEREG16(0x4000030)
#define BG3PB DEFINEREG16(0x4000032)
#define BG3PC DEFINEREG16(0x4000034)
#define BG3PD DEFINEREG16(0x4000036)
#define BG3X DEFINEREG32(0x4000038)
#define BG3Y DEFINEREG32(0x400003C)
#define WIN0H DEFINEREG16(0x4000040)
#define WIN1H DEFINEREG16(0x4000042)
#define WIN0V DEFINEREG16(0x4000044)
#define WIN1V DEFINEREG16(0x4000046)
#define WININ DEFINEREG16(0x4000048)
#define WINOUT DEFINEREG16(0x400004A)
#define MOSAIC DEFINEREG16(0x400004C)
#define BLDCNT DEFINEREG16(0x4000050)
#define BLDALPHA DEFINEREG16(0x4000052)
#define BLDY DEFINEREG16(0x4000054)
// TODO SOUND REGS
#define DMA0SAD DEFINE_REG32(0x40000B0)
#define DMA0DAD DEFINE_REG32(0x40000B4)
#define DMA0CNTL DEFINE_REG16(0X40000B8)
#define DMA0CNTH DEFINE_REG16(0X40000BA)
#define DMA1SAD DEFINE_REG32(0X40000BC)
#define DMA1DAD DEFINE_REG32(0X40000C0)
#define DMA1CNTL DEFINE_REG16(0X40000C4)
#define DMA1CNTH DEFINE_REG16(0X40000C6)
#define DMA2SAD DEFINE_REG32(0X40000C8)
#define DMA2DAD DEFINE_REG32(0X40000CC)
#define DMA2CNTL DEFINE_REG16(0X40000D0)
#define DMA2CNTH DEFINE_REG16(0X40000D2)
#define DMA3SAD DEFINE_REG32(0X40000D4)
#define DMA3DAD DEFINE_REG32(0X40000D8)
#define DMA3CNTL DEFINE_REG16(0X40000DC)
#define DMA3CNTH DEFINE_REG16(0X40000DE)
/*
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
*/
#undef DEFINE_REG16()
#undef DEFINE_REG32()
bios.c
/**
divisione hardware
ritorna in 800d TODO pointer
0 div
1 mod
2 abs div
*/
__attribute__ ((noinline)) void bios_div_single (u32 num, u32 den, u32 func)
{
asm ("push {r0-r4}");
ASM_800D_R4;
asm ("swi 0x7");
asm ("cmp r2, #0");
asm ("bne bios_div_single_cmp1");
asm ("str r0, [r4]");
asm (".bios_div_single_cmp1:");
asm ("cmp r2, #1");
asm ("bne bios_div_single_cmp2");
asm ("str r1, [r4]");
asm (".bios_div_single_cmp2:");
asm ("cmp r2, #2");
asm ("bne .bios_div_single_exit");
asm ("str r3, [r4]");
asm (".bios_div_single_exit:");
asm ("push {r0-r4}");
}
__attribute__ ((noinline)) void bios_div_multi (u32 num, u32 den, u32* alloc)
{
asm ("push {r0-r4}");
asm ("swi 0x7");
asm("str r0, [r2]");
asm("str r1, [r2,#4]");
asm("str r3, [r2,#8]");
asm ("push {r0-r4}");
}
/*
BIOS Function Summary
GBA NDS7 NDS9 DSi7 DSi9 Basic Functions
00h 00h 00h - - SoftReset
01h - - - - RegisterRamReset
02h 06h 06h 06h 06h Halt
03h 07h - 07h - Stop/Sleep
04h 04h 04h 04h 04h IntrWait ;DSi7/DSi9: both bugged?
05h 05h 05h 05h 05h VBlankIntrWait ;DSi7/DSi9: both bugged?
06h 09h 09h 09h 09h Div
07h - - - - DivArm
08h 0Dh 0Dh 0Dh 0Dh Sqrt
09h - - - - ArcTan
0Ah - - - - ArcTan2
0Bh 0Bh 0Bh 0Bh 0Bh CpuSet
0Ch 0Ch 0Ch 0Ch 0Ch CpuFastSet
0Dh - - - - GetBiosChecksum
0Eh - - - - BgAffineSet
0Fh - - - - ObjAffineSet
GBA NDS7 NDS9 DSi7 DSi9 Decompression Functions
10h 10h 10h 10h 10h BitUnPack
11h 11h 11h 11h 11h LZ77UnCompReadNormalWrite8bit ;"Wram"
12h - - - - LZ77UnCompReadNormalWrite16bit ;"Vram"
- - - 01h 01h LZ77UnCompReadByCallbackWrite8bit
- 12h 12h 02h 02h LZ77UnCompReadByCallbackWrite16bit
- - - 19h 19h LZ77UnCompReadByCallbackWrite16bit (same as above)
13h - - - - HuffUnCompReadNormal
- 13h 13h 13h 13h HuffUnCompReadByCallback
14h 14h 14h 14h 14h RLUnCompReadNormalWrite8bit ;"Wram"
15h - - - - RLUnCompReadNormalWrite16bit ;"Vram"
- 15h 15h 15h 15h RLUnCompReadByCallbackWrite16bit
16h - 16h - 16h Diff8bitUnFilterWrite8bit ;"Wram"
17h - - - - Diff8bitUnFilterWrite16bit ;"Vram"
18h - 18h - 18h Diff16bitUnFilter
GBA NDS7 NDS9 DSi7 DSi9 Sound (and Multiboot/HardReset/CustomHalt)
19h 08h - 08h - SoundBias
1Ah - - - - SoundDriverInit
1Bh - - - - SoundDriverMode
1Ch - - - - SoundDriverMain
1Dh - - - - SoundDriverVSync
1Eh - - - - SoundChannelClear
1Fh - - - - MidiKey2Freq
20h - - - - SoundWhatever0
21h - - - - SoundWhatever1
22h - - - - SoundWhatever2
23h - - - - SoundWhatever3
24h - - - - SoundWhatever4
25h - - - - MultiBoot
26h - - - - HardReset
27h 1Fh - 1Fh - CustomHalt
28h - - - - SoundDriverVSyncOff
29h - - - - SoundDriverVSyncOn
2Ah - - - - SoundGetJumpList
GBA NDS7 NDS9 DSi7 DSi9 New NDS Functions
- 03h 03h 03h 03h WaitByLoop
- 0Eh 0Eh 0Eh 0Eh GetCRC16
- 0Fh 0Fh - - IsDebugger
- 1Ah - 1Ah - GetSineTable
- 1Bh - 1Bh - GetPitchTable (DSi7: bugged)
- 1Ch - 1Ch - GetVolumeTable
- 1Dh - 1Dh - GetBootProcs (DSi7: only 1 proc)
- - 1Fh - 1Fh CustomPost
GBA NDS7 NDS9 DSi7 DSi9 New DSi Functions (RSA/SHA1)
- - - 20h 20h RSA_Init_crypto_heap
- - - 21h 21h RSA_Decrypt
- - - 22h 22h RSA_Decrypt_Unpad
- - - 23h 23h RSA_Decrypt_Unpad_GetChunk04
- - - 24h 24h SHA1_Init
- - - 25h 25h SHA1_Update
- - - 26h 26h SHA1_Finish
- - - 27h 27h SHA1_Init_update_fin
- - - 28h 28h SHA1_Compare_20_bytes
- - - 29h 29h SHA1_Random_maybe
GBA NDS7 NDS9 DSi7 DSi9 Invalid Functions
2Bh+ 20h+ 20h+ - - Crash (SWI xxh..FFh do jump to garbage addresses)
- xxh xxh - - Jump to 0 (on any SWI numbers not listed above)
- - - 12h 12h No function (ignored)
- - - 2Bh 2Bh No function (ignored)
- - - 40h+ 40h+ Mirror (SWI 40h..FFh mirror to 00h..3Fh)
- - - xxh xxh Hang (on any SWI numbers not listed above)
*/
ho scelto l'attributo noinline perchè pensavo che magari senza mi avrebbe incasinato i registri delle funzioni in asm...
math.c
/**
divisione hardware
ritorna in 800d TODO pointer
0 div
1 mod
2 abs div
*/
void math_div_single(int a)
{
}
void math_div_multiple(u32 n, u32 d, boolean allocNeed, u32 offs)
{
/*
if (allocNeed)
{
util_memAlloc32(3);
offs =(u32*) OFFSET_AS_POINTER32(var_0x800D);
}
else
{
}
*/
//bios_div_multi(n, d, offs);
// return offs;
}
text.c
/**
scrive un carattere. USO INTERNO.
x e y del gba, non della console.
*/
void text_putc16bpp(u8 chr, u8 x, u8 y, T_COLOR clr)
{
u32 chra=0;
u32 chrb=0;
// rendere funzione o lut o vram
//tonc
if (chr== 'a')
{
chra=0x7E66663C;
chrb=0x00666666;
}
// FINE RENDERE
util_memAlloc32(3);
u32* div =(u32*) OFFSET_AS_POINTER32(var_0x800D);
u32 i =0;
for (; i<32; i++)
{
BREAKPOINT;
//math_div_multiple (i,8, FALSE, div);
bios_div_multi(i, 8, div);
video_plotPixelM3inline(x+*(div++), y+*(div--),clr*(chra&1) );
//fare in ++ e if 8 =0
// TODO SVUOTA IL LOOP
chra>>=1;
}
for (int i=0; i<32; i++)
{
//math_div_multiple (i,8, FALSE, div);
bios_div_multi(i, 8, div);
video_plotPixelM3inline(x+*(div++), y+4+*(div--),clr*(chrb&1) );
// TODO SVUOTA IL LOOP
chrb>>=1;
}
//TODO DISEGNA 2 PX ALLA VOLTA
}
util.c
void util_memcpy32(u32 dst, u32 src, u32 wdcount)
{
while (wdcount--)
{
OFFSET_AS_POINTER32(dst)=OFFSET_AS_POINTER32(src);
dst+=4;
src+=4;
}
}
__attribute__ ((noinline)) void util_blockFill(u32 dest, u32 lung, u32 filler)
{
//memAlloc(12);
//u32 ofpoint=OFFSET_AS_POINTER32(var_0x800D);
//u32* mem =(u32*) ofpoint;
//u32* mem =(u32*) OFFSET_AS_POINTER32(var_0x800D);
//mem[0]=dest;
//mem[1]=lung;
//mem[2]=filler;
//VERSIONE C
//eppure mi sembra giusto :c
while(lung--)
{
*((u32*)dest)=filler;
dest+=4;
}
/*
asm ("push {r0-r3}");
asm ("mov r0, #2");
asm (" lsl r0, #0x8");
asm ("add r0, r0, #2");
asm ("lsl r0, #0x4");
asm ("add r0, r0, #14");
asm ("lsl r0, #0x4");
asm ("add r0, r0, #8");
asm ("lsl r0, #0x4");
asm ("add r0, r0, #13");
asm ("lsl r0, #0x4");
asm ("add r0, r0, #12");
//fin qui ho creato la var 800D 0202E8DC
asm ("ldr r0, [r0]");
//carico il vettore nei reg:
asm ("add r0, r0, #8");
asm ("ldr r2,[r0]");
asm ("sub r0, r0, #4");
asm ("ldr r1,[r0]");
asm ("sub r0, r0, #4");
asm ("ldr r0, [r0]");
//loop che scrive e decrementa:
// r0 dest r1 lung r2 fill
asm ("lsl r1, #0x2");
asm ("add r1, r0, r1");
asm (".util_blockfill_main_loop:");
asm ("str r2, [r0]");
asm ("add r0, r0, #4");
asm ("cmp r0, r1"); // TODO QUA LOOPA
asm ("bne util_blockfill_main_loop");
asm ("pop {r0-r3}");
*/
//memFree((u32)mem);
}
/**
mette in 800d+f l'indirizzo di uno spazio di ram
grande almeno lung parole da 32 bit
*/
__attribute__ ((noinline)) void util_memAlloc32 (u32 lung)
{
// NOTA: IN ASM GIUSTO
//asm ("push {r0-r4}");
//asm ("mov r3, #0");
//asm ("mov r1, #1");
//asm ("lsl r1, #0x19");
// 1<<25=0x2000000
//asm (".util_memAlloc32_loop:");
//asm ("ldr r2, [r1]");
//asm ("cmp r2, #0");
//asm ("beq .util_memAlloc32_trovato"); // piu probabilr ke sia != percio non svuoto la pipeline
//asm ("mov r3, #0");//resetto il counter
//asm ("add r1, r1, #4");
/*
asm ("b .util_memAlloc32_loop");
asm (".util_memAlloc32_trovato:");
asm ("add r3, r3, #1");
asm ("add r1, r1, #4");
asm ("cmp r3, r0");
asm ("bne .util_memAlloc32_loop");
//-------
asm ("mov r3, #4");
asm ("mul r0, r3");
asm ("sub r1, r1, r0");
//-----------------
asm ("mov r4, #2");
asm (" lsl r4, #0x8");
asm ("add r4, r4, #2");
asm ("lsl r4, #0x4");
asm ("add r4, r4, #14");
asm ("lsl r4, #0x4");
asm ("add r4, r4, #8");
asm ("lsl r4, #0x4");
asm ("add r4, r4, #13");
asm ("lsl r4, #0x4");
asm ("add r4, r4, #12");
//fin qui ho creato la var 800D 0202E8DC
*/
//asm("str r0, [r4]");
//mette il risultato nella var 800d e seguente f
//asm ("pop {r0-r4}");
u32 ofs=0x2000000;
u32 count=1;
count--;
while (ofs<256*1024)
{
if (!(OFFSET_AS_POINTER32(ofs))) //se a ofs c'e zero
{ count++;
}
else
{ count=0;
}
if (lung==count) break;
ofs++;
}
OFFSET_AS_POINTER32(var_0x800D)=ofs-lung*4;
}
void util_memFree32(u32 offs, u32 size)
{
util_blockFill(offs, size, 0x0);
}
video.c
//================== DICHIARAZIONI ==================
//================== DEFINIZIONI ==================
/**
BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)
Display Frame Select (0-1=Frame 0-1) (for BG Modes 4,5 only)
H-Blank Interval Free (1=Allow access to OAM during H-Blank)
OBJ Character VRAM Mapping (0=Two dimensional, 1=One dimensional)
Forced Blank (1=Allow FAST access to VRAM,Palette,OAM)
Screen Display BG0 (0=Off, 1=On)
Screen Display BG1 (0=Off, 1=On)
Screen Display BG2 (0=Off, 1=On)
Screen Display BG3 (0=Off, 1=On)
Screen Display OBJ (0=Off, 1=On)
Window 0 Display Flag (0=Off, 1=On)
Window 1 Display Flag (0=Off, 1=On)
OBJ Window Display Flag (0=Off, 1=On)
*/
void video_initDispCntGlobal(u8 bgMode, boolean frame, boolean hBlank, boolean objMapping, boolean forceBlank, boolean bg0, boolean bg1, boolean bg2, boolean bg3, boolean obj, boolean win0, boolean win1, boolean winObj)
{
u16 newreg=video_createDispCnt(bgMode, frame, hBlank, objMapping, forceBlank, bg0, bg1, bg2, bg3, obj, win0, win1, winObj);
if (newreg!=0)
DISPCNT=newreg;
}
/**
choose the property to set between DISPCNT_XXX_PROPERTY
if bgmode, flag ignored
if other property, bgmode ignored
*/
void video_setDispCntProperties(u8 property, u8 bgMode, boolean flag)
{
u16 newreg=0;
u16 oldreg = DISPCNT;
if (property!=DISPCNT_BGMODE_PROPERTY)
newreg=flag<<property;
// else if (!(bgMode>5)) newreg = bgMode;
DISPCNT= (oldreg^newreg);
}
/**
PRIVATE USE
*/
u16 video_createDispCnt(u8 bgMode, boolean frame, boolean hBlank, boolean objMapping, boolean forceBlank, boolean bg0, boolean bg1, boolean bg2, boolean bg3, boolean obj, boolean win0, boolean win1, boolean winObj)
{
if (!(bgMode>5))
return (bgMode|(frame<<4)|(hBlank<<5)|(objMapping<<6)|(forceBlank<<7)|(bg0<<7)|(bg1<<8)|(bg2<<9)|(bg2<<10)|(bg3<<11)|(obj<<12)|(win0<<13)|(win1<<14)|(winObj<<15));
else return 0;
}
T_COLOR video_alphaBlend(T_COLOR source, T_COLOR newcol, u8 coef)
{
/*
float alpha=coef/255;
{
float ra = getR(source)/MAX_COLOR_VALUE;
float ga = getG(source)/MAX_COLOR_VALUE;
float ba = getB(source)/MAX_COLOR_VALUE;
float rb = getR(newcol)/MAX_COLOR_VALUE;
float gb = getG(newcol)/MAX_COLOR_VALUE;
float bb = getB(newcol)/MAX_COLOR_VALUE;
float rt= alpha * (rb - ra) + ra;
float gt= alpha * (gb - ga) + ga;
float bt= alpha * (bb - ba) + ba;
int rd =(int)(rt*MAX_COLOR_VALUE);
int gd=(int)(gt*MAX_COLOR_VALUE);
int bd=(int)(bt*MAX_COLOR_VALUE);
return RGB16(rd,gd,bd);
}
else<*/ return 0x8000; //colore invalido
}
void video_plotPixelM3(u8 x, u8 y, T_COLOR color, boolean transp)
{
if (!((transp)&&(color>0x7fff )))
((u16*)0x06000000)[x+y*SCREEN_WIDTH] = color;
}
inline void video_plotPixelM3inline (int x, int y, T_COLOR clr)
{ (( u16*)0x06000000)[y*SCREEN_WIDTH+x]= clr; }
int video_getR(T_COLOR c)
{ return (c&31); }
int video_getG(T_COLOR c)
{ return ((c&992)>>5); }
int video_getB(T_COLOR c)
{ return ((c&31744)>>10); }
grazie e buonasera