okis :rever: :rever:
Ya estoy de vacas y puedo empezar a hacer cosas no remuneradas... xD.
El truco esta en el static xD.
No te tiene que hacer ligadadura de librerias dinamicas de hilos (phread) sino estática.
arm-linux-gcc -static-c minimal.c -o minimal.o
arm-linux-gcc -static -c ejemplo.c -o ejemplo.o
arm-linux-gcc -static minimal.o ejemplo.o -o salida.gpe
static, static, static he ahí la cuestión y ya esta.
A rlyeh parece que le mola el C y controla bastante.
Utiliza bastante operadores binarios de esplazamiento porque supongo que vendrán puestas
así las direcciones en el documento de características de magic eyes, pero luego al ensamblar
todos esos operadores que utilizan solo constantes se compila como un numero mas:
arm-linux-gcc -static -S minimal.c -o minimal_arm.asm
Que mas decir: le ha metido un atexit para ejecutar el código de cierre de dispositivos y arrancar
de nuevo el menu de la GP2X, por lo que no hay que añadir esta función al salir de nuestra aplicación.
El resto son un huevo de mapeados de punteros y demás virguerías y creo haber leido
que quita el uso de interrupciones un momento (no se si de software o hardware) para toquitear los
registros del procesador, cuestión que me parece brutal ya que debería ser manejada por el sistema operativo,
pero como los de GPH no han dado el soporte debido pues.. kkita pa nosostros.
Me compila con el GP2X_devkit en linux y windows (cygwin como shell), con gcc o con g++.
Eso si si no esta -static al hacer el link me sale que no encuentra no se que directorio al
enlazar las pthread (solo en windows)... -lpthread las librerias GNU de hilos.
Pero como digo la cuestión está en los static.
Un gran trabajo desde luego!!
Thanks rlyeh.
He aquí la versión limpia de la librería... respetando las llaves y sangrías de las competencias.
/*
EGO - Emisor of Graphical Objects (by newage, Gp32Spain.com)
This module is the minimal library v0.A by rlyeh, (c) 2005.
Thanks to Squidge, Robster, snaff, Reesy and NK, for the help & previous work! :-)
License
=======
Free for non-commercial projects (it would be nice receiving a mail from you).
Other cases, ask me first.
GamePark Holdings is not allowed to use this library and/or use parts from it.
EGO License
===========
Extends the GP2X minimal library license by Rlyeh.
*/
/*
* Headers
*/
#include <fcntl.h>
#include <linux/fb.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <sys/time.h>
#include <unistd.h>
#ifndef __MINIMAL_H__
#define __MINIMAL_H__
/*
* Defines
*/
#define MINILIB_VERSION "GP2X minimal library v0.A by rlyeh, (c) 2005."
#define GP2X_QUEUE_MAX_ITEMS 16
#define GP2X_QUEUE_ARRAY_PTR ((0x1000-(sizeof(gp2x_queue)<<2)))
#define GP2X_QUEUE_DATA_PTR (GP2X_QUEUE_ARRAY_PTR-(GP2X_QUEUE_MAX_ITEMS<<2))
#define gp2x_2ndcore_code(v) (*(volatile unsigned long *)(v))
#define gp2x_1stcore_code(v) gp2x_dualcore_ram[(v)>>2]
#define gp2x_2ndcore_data(v) gp2x_2ndcore_code((v)+0x100000)
#define gp2x_1stcore_data(v) gp2x_1stcore_code((v)+0x100000)
#define gp2x_dualcore_data(v) gp2x_1stcore_data(v)
#define gp2x_2ndcore_code_ptr(v) ((volatile unsigned long *)(v))
#define gp2x_1stcore_code_ptr(v) (&gp2x_dualcore_ram[(v)>>2])
#define gp2x_2ndcore_data_ptr(v) gp2x_2ndcore_code_ptr((v)+0x100000)
#define gp2x_1stcore_data_ptr(v) gp2x_1stcore_code_ptr((v)+0x100000)
#define gp2x_video_wait_vsync() while(gp2x_memregs[0x1182>>1]&(1<<4));
#define gp2x_video_wait_hsync() while(gp2x_memregs[0x1182>>1]&(1<<5));
#define gp2x_video_color8(C,R,G,B) do gp2x_palette[((C)<<1)+0]=((G)<<8)|(B),gp2x_palette[((C)<<1)+1]=(R); while(0)
#define gp2x_video_color15(R,G,B,A) ((((R)&0xF8)<<8)|(((G)&0xF8)<<3)|(((B)&0xF8)>>3)|((A)<<5))
#define gp2x_dualcore_declare_subprogram(name) extern void gp2x_dualcore_launch_## name ##_subprogram(void);
#define gp2x_dualcore_launch_subprogram(name) gp2x_dualcore_launch_## name ##_subprogram()
/*
* Struct Type Definitions
*/
typedef struct gp2x_queue
{
volatile unsigned long head;
volatile unsigned long tail;
volatile unsigned long items;
volatile unsigned long max_items;
unsigned long *place920t;
unsigned long *place940t;
} gp2x_queue;
typedef struct gp2x_rect
{
int x;
int y;
int w;
int h;
int solid;
unsigned short *data15;
unsigned char *data8;
} gp2x_rect;
enum
{
GP2X_UP=0x1,
GP2X_LEFT=0x4,
GP2X_DOWN=0x10,
GP2X_RIGHT=0x40,
GP2X_START=1<<8,
GP2X_SELECT=1<<9,
GP2X_L=1<<10,
GP2X_R=1<<11,
GP2X_A=1<<12,
GP2X_B=1<<13,
GP2X_X=1<<14,
GP2X_Y=1<<15,
GP2X_VOL_UP=1<<23,
GP2X_VOL_DOWN=1<<22,
GP2X_PUSH=1<<27
};
/*
* API Functions
*/
extern volatile unsigned short gp2x_palette[512];
extern unsigned short *gp2x_screen15;
extern unsigned char *gp2x_screen8;
extern volatile unsigned long *gp2x_dualcore_ram;
extern void gp2x_video_flip(void);
extern void gp2x_video_setgamma(unsigned short);
extern void gp2x_video_setpalette(void);
extern void gp2x_blitter_rect15(gp2x_rect *);
extern void gp2x_blitter_rect8(gp2x_rect *);
extern unsigned long gp2x_joystick_read(void);
extern void gp2x_sound_volume(int, int);
extern void gp2x_sound_pause(int);
extern void gp2x_sound_frame (void *blah, void *bufferg, int samples);
extern void gp2x_timer_delay(unsigned long);
extern unsigned long gp2x_timer_read(void);
static void gp2x_initqueue(gp2x_queue *, unsigned long, unsigned long *, unsigned long *);
static void gp2x_enqueue(gp2x_queue *, unsigned long);
extern void gp2x_dualcore_enable(int);
extern void gp2x_dualcore_pause(int);
extern void gp2x_dualcore_sync(void);
extern void gp2x_dualcore_exec(unsigned long);
extern void gp2x_dualcore_launch_program(unsigned long *, unsigned long);
extern void gp2x_dualcore_launch_program_from_disk(const char *, unsigned long, unsigned long);
extern int fcloseall(void);
extern void gp2x_init(int, int, int, int, int, int);
extern void gp2x_deinit(void);
#endif // __MINIMAL_H__
#include "HardWareCore.h"
unsigned char *gp2x_screen8;
unsigned char *gp2x_upperRAM;
unsigned long gp2x_dev[8] = {0,0,0,0,0,0,0,0};
unsigned long gp2x_physvram[8];
unsigned long *gp2x_memregl;
unsigned long gp2x_volume;
unsigned long gp2x_ticks_per_second;
volatile unsigned long gp2x_sound_pausei=1;
volatile unsigned long gp2x_ticks=0;
volatile unsigned long gp2x_sound=0;
volatile unsigned long *gp2x_dualcore_ram;
unsigned short *gp2x_memregs;
unsigned short *gp2x_screen15;
unsigned short *gp2x_logvram15[4];
/*
* 25 Hz gives our biggest supported sampling buffer
*/
unsigned short gp2x_sound_buffer[4+((44100/25)*2)*8];
volatile unsigned short gp2x_palette[512];
pthread_t gp2x_sound_thread=0;
void gp2x_video_flip(void)
{
unsigned long address=gp2x_physvram[gp2x_physvram[7]];
if(++gp2x_physvram[7]==4) gp2x_physvram[7]=0;
gp2x_screen15=gp2x_logvram15[gp2x_physvram[7]];
gp2x_screen8=(unsigned char *)gp2x_screen15;
gp2x_memregs[0x290E>>1]=(unsigned short)(address & 0xFFFF);
gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16);
gp2x_memregs[0x2912>>1]=(unsigned short)(address & 0xFFFF);
gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16);
}
/*
* 0..255
*/
void gp2x_video_setgamma(unsigned short gamma)
{
int i=256*3;
gp2x_memregs[0x295C>>1] = 0;
while(i--)
{
gp2x_memregs[0x295E>>1] = gamma;
}
}
void gp2x_video_setpalette(void)
{
unsigned short *g=(unsigned short *)gp2x_palette;
int i=512;
gp2x_memregs[0x2958>>1] = 0;
while(i--)
{
gp2x_memregs[0x295A>>1] = *g++;
}
}
void gp2x_blitter_rect15(gp2x_rect *r)
{
int x;
int y;
unsigned short *data=r->data15;
unsigned short *offset=&gp2x_screen15[r->x+r->y*320];
y=r->h;
if(r->solid)
{
while(y--)
{
x=r->w;
while(x--)
{
*offset++=*data++;
}
offset+=320-x;
}
}
else
{
while(y--)
{
x=r->w;
while(x--)
{
if(*data){
*offset = *data;
}
offset++;
data++;
}
offset+=320-x;
}
}
}
void gp2x_blitter_rect8(gp2x_rect *r)
{
int x;
int y;
unsigned char *data=r->data8;
unsigned char *offset = &gp2x_screen8[r->x+r->y*320];
y=r->h;
if(r->solid)
{
while(y--)
{
x=r->w;
while(x--)
{
*offset++ = *data++;
offset+=320-x;
}
}
}
else
{
while(y--)
{
x=r->w;
while(x--)
{
if(*data)
{
*offset=*data;
}
offset++;
data++;
}
offset+=320-x;
}
}
}
unsigned long gp2x_joystick_read(void)
{
unsigned long value = (gp2x_memregs[0x1198>>1] & 0x00FF);
if(value==0xFD)
{
value=0xFA;
}
if(value==0xF7)
{
value=0xEB;
}
if(value==0xDF)
{
value=0xAF;
}
if(value==0x7F)
{
value=0xBE;
}
return ~((gp2x_memregs[0x1184>>1] & 0xFF00) | value | (gp2x_memregs[0x1186>>1] << 16));
}
void gp2x_sound_volume(int l, int r)
{
/*
* 0x5A, 0x60
*/
l = (((l*0x50)/100)<<8)|((r*0x50)/100);
/*
* SOUND_MIXER_WRITE_VOLUME
*/
ioctl(gp2x_dev[4], SOUND_MIXER_WRITE_PCM, &l);
}
void gp2x_timer_delay(unsigned long ticks)
{
unsigned long target=gp2x_memregl[0x0A00>>2]+ticks*gp2x_ticks_per_second;
while(gp2x_memregl[0x0A00>>2]<target)
{
;
}
}
unsigned long gp2x_timer_read(void)
{
return gp2x_memregl[0x0A00>>2]/gp2x_ticks_per_second;
}
void gp2x_sound_pause(int yes) { gp2x_sound_pausei=yes; }
static void *gp2x_sound_play(void *blah)
{
int flip=0, flyp=gp2x_sound_buffer[1];
struct timespec ts;
ts.tv_sec=0;
ts.tv_nsec = gp2x_sound_buffer[2];
while(!gp2x_sound)
{
nanosleep(&ts, NULL);
if(!gp2x_sound_pausei)
{
gp2x_sound_frame(blah, (void *)(&gp2x_sound_buffer[4+flip]), gp2x_sound_buffer[0]);
write(gp2x_dev[3], (void *)(&gp2x_sound_buffer[4+flyp]), gp2x_sound_buffer[1]);
flip+=gp2x_sound_buffer[1]; if(flip==gp2x_sound_buffer[1]*8) flip=0;
flyp+=gp2x_sound_buffer[1]; if(flyp==gp2x_sound_buffer[1]*8) flyp=0;
}
}
return NULL;
}
static void gp2x_initqueue(gp2x_queue *q, unsigned long queue_items, unsigned long *position920t, unsigned long *position940t)
{
q->head = q->tail = q->items = 0;
q->max_items = queue_items;
if(position920t)
{
q->place920t=position920t;
}
else
{
q->place920t=(unsigned long *)malloc(sizeof(unsigned long) * queue_items);
}
if(position940t)
{
q->place940t=position940t;
}
memset(q->place920t, 0, sizeof(unsigned long) * queue_items);
}
static void gp2x_enqueue(gp2x_queue *q, unsigned long data)
{
/*
* waiting for tail to decrease...
*/
while(q->items==q->max_items)
{
;
}
q->place920t[q->head = (q->head < q->max_items ? q->head+1 : 0)] = data;
q->items++;
}
void gp2x_dualcore_pause(int yes)
{
if(yes)
{
gp2x_memregs[0x0904>>1] &= 0xFFFE;
}
else
{
gp2x_memregs[0x0904>>1] |= 1;
}
}
static void gp2x_940t_reset(int yes)
{
gp2x_memregs[0x3B48>>1] = ((yes&1) << 7) | (0x03);
}
static void gp2x_940t_pause(int yes)
{
gp2x_dualcore_pause(yes);
}
static void gp2x_dualcore_registers(int save)
{
static unsigned short regs[8];
if(save)
{
regs[0]=gp2x_memregs[0x0904>>1]; regs[1]=gp2x_memregs[0x0912>>1];
regs[2]=gp2x_memregs[0x091c>>1]; regs[3]=gp2x_memregs[0x3b40>>1];
regs[4]=gp2x_memregs[0x3b42>>1]; regs[5]=gp2x_memregs[0x3b48>>1];
regs[6]=gp2x_memregs[0x3b44>>1]; regs[7]=gp2x_memregs[0x3b46>>1];
gp2x_940t_reset(1);
gp2x_940t_pause(1);
}
else
{
gp2x_memregs[0x0904>>1]=regs[0]; gp2x_memregs[0x0912>>1]=regs[1];
gp2x_memregs[0x091c>>1]=regs[2]; gp2x_memregs[0x3b40>>1]=regs[3];
gp2x_memregs[0x3b42>>1]=regs[4]; gp2x_memregs[0x3b48>>1]=regs[5];
gp2x_memregs[0x3b44>>1]=regs[6]; gp2x_memregs[0x3b46>>1]=regs[7];
}
}
void gp2x_dualcore_sync(void)
{
gp2x_queue *q = (gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR);
while(q->items)
{
;
}
}
void gp2x_dualcore_exec(unsigned long command)
{
gp2x_enqueue((gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR),comm and);
}
void gp2x_dualcore_launch_program(unsigned long *area, unsigned long size)
{
unsigned long i=0, *arm940t_ram=(unsigned long *)gp2x_dualcore_ram;
gp2x_940t_reset(1);
/*
* Disable interrupts
*/
gp2x_memregs[0x3B40>>1] = 0;
gp2x_memregs[0x3B42>>1] = 0;
gp2x_memregs[0x3B44>>1] = 0xffff;
gp2x_memregs[0x3B46>>1] = 0xffff;
gp2x_940t_pause(0);
while(i < size)
{
*arm940t_ram++=area[i++];
}
gp2x_initqueue((gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR),
GP2X_QUEUE_MAX_ITEMS, (unsigned long *)gp2x_1stcore_data_ptr(GP2X_QUEUE_DATA_PTR),
(unsigned long *)gp2x_2ndcore_data_ptr(GP2X_QUEUE_DATA_PTR));
gp2x_940t_reset(0);
}
void gp2x_dualcore_launch_program_from_disk(const char *file, unsigned long offset, unsigned long size)
{
FILE *in;
void *data;
if((in=fopen(file, "rb"))==NULL)
{
return;
}
if((data=malloc(size))==NULL)
{
fclose(in);
return;
}
fseek(in, 0L, offset);
fread(data, 1, size, in);
gp2x_dualcore_launch_program((unsigned long *)data, size);
free(data);
fclose(in);
}
void gp2x_init(int ticks_per_second, int bpp, int rate, int bits, int stereo, int Hz)
{
struct fb_fix_screeninfo fixed_info;
static int first = 1;
gp2x_ticks_per_second = 7372800 / ticks_per_second;
if(!gp2x_dev[0])
{
gp2x_dev[0] = open("/dev/fb0", O_RDWR);
}
if(!gp2x_dev[1])
{
gp2x_dev[1] = open("/dev/fb1", O_RDWR);
}
if(!gp2x_dev[2])
{
gp2x_dev[2] = open("/dev/mem", O_RDWR);
}
if(!gp2x_dev[3])
{
gp2x_dev[3] = open("/dev/dsp", O_WRONLY);
}
if(!gp2x_dev[4])
{
gp2x_dev[4] = open("/dev/mixer", O_RDWR);
}
gp2x_dualcore_ram=(unsigned long *)mmap(0, 0x1000000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x03000000);
gp2x_memregl=(unsigned long *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0xc0000000);
gp2x_memregs=(unsigned short *)gp2x_memregl;
if(first)
{
printf(MINILIB_VERSION "\n");
gp2x_dualcore_registers(1);
gp2x_sound_volume(100,100);
gp2x_memregs[0x0F16>>1] = 0x830a;
usleep(100000);
gp2x_memregs[0x0F58>>1] = 0x100c;
usleep(100000);
}
ioctl(gp2x_dev[gp2x_physvram[7]=0], FBIOGET_FSCREENINFO, &fixed_info);
gp2x_screen15=gp2x_logvram15[2]=gp2x_logvram15[0]=(unsigned short *)mmap(0, 320*240*2, PROT_WRITE, MAP_SHARED, gp2x_dev[0], 0);
gp2x_screen8=(unsigned char *)gp2x_screen15;
gp2x_physvram[2]=gp2x_physvram[0]=fixed_info.smem_start;
ioctl(gp2x_dev[1], FBIOGET_FSCREENINFO, &fixed_info);
gp2x_logvram15[3]=gp2x_logvram15[1]=(unsigned short *)mmap(0, 320*240*2, PROT_WRITE, MAP_SHARED, gp2x_dev[1], 0);
gp2x_physvram[3]=gp2x_physvram[1]=fixed_info.smem_start;
/*
* 8/15/16/24bpp...
*/
gp2x_memregs[0x28DA>>1]=(((bpp+1)/8)<<9)|0xAB;
/*
* line width in bytes
*/
gp2x_memregs[0x290C>>1]=320*((bpp+1)/8);
memset(gp2x_screen15, 0, 320*240*2); gp2x_video_flip();
memset(gp2x_screen15, 0, 320*240*2); gp2x_video_flip();
if(bpp==8){
gp2x_physvram[2]+=320*240;
gp2x_physvram[3]+=320*240;
gp2x_logvram15[2]+=320*240/2;
gp2x_logvram15[3]+=320*240/2;
}
ioctl(gp2x_dev[3], SNDCTL_DSP_SPEED, &rate);
ioctl(gp2x_dev[3], SNDCTL_DSP_SETFMT, &bits);
ioctl(gp2x_dev[3], SNDCTL_DSP_STEREO, &stereo);
gp2x_sound_buffer[1]=(gp2x_sound_buffer[0] = (rate/Hz)) << (stereo + (bits==16));
gp2x_sound_buffer[2]=(1000000/Hz);
if(first)
{
pthread_create(&gp2x_sound_thread, NULL, gp2x_sound_play, NULL);
/*
* Run this void function before exit
*/
atexit(gp2x_deinit);
first=0;
}
}
void gp2x_deinit(void)
{
/*
* Wait arm920t threads to finish
*/
while((gp2x_sound++)<1000000)
{
;
}
gp2x_dualcore_registers(0);
/*
* Set video mode
*/
gp2x_memregs[0x28DA>>1]=0x4AB;
gp2x_memregs[0x290C>>1]=640;
{
int i;
/*
* Close all devices
*/
for(i=0;i<8;i++)
{
if(gp2x_dev[i])
{
close(gp2x_dev[i]);
}
}
}
/*
* Close all files
*/
fcloseall();
/*
* Go to menu
*/
chdir("/usr/gp2x");
execl("gp2xmenu","gp2xmenu",NULL);
}
/*
GP2X minimal library by rlyeh, 2005. emulnation.info@rlyeh (swap it!)
License
=======
Free for non-commercial projects (it would be nice receiving a mail from you).
Other cases, ask me first.
GamePark Holdings is not allowed to use this library and/or use parts from it.
------------------------------------------------------------------------------
Simple sample to show you how to use palettes.
*/
#include "HardWareCore.h"
int main(int argc, char *argv[])
{
gp2x_init(1000, 8, 11025,16,1,60);
while(1)
{
unsigned long pad=gp2x_joystick_read(), R=0,G=0,B=0;
if(pad & GP2X_L) if(pad & GP2X_R) exit(0);
if(pad & GP2X_A) R=255;
if(pad & GP2X_X) G=255;
if(pad & GP2X_B) B=255;
gp2x_video_color8(0,R,G,B);
gp2x_video_setpalette();
}
}
void gp2x_sound_frame(void *blah, void *buff, int samples) {}
/*
compilation:
arm-linux-gcc minimal.c 8bits.c -static -lpthread
output:
different color patterns when you press buttons.
L+R to exit.
*/
# Makefile para ego, por newage.
C++ = arm-linux-g++
CC = arm-linux-gcc
DEL = rm
DIROBJ = ./../.obj/
DIRSRC = ./../src/
DIRINC = $(DIRSRC)header/
DIRCOD = $(DIRSRC)source/
FLAGS = -static -c -I"$(DIRINC)"
SALIDA = ./../ego.gpe
DOXYGEN = ./../doc/doxygen/doxygen
DOXYFILE = ./../doc/doxygen/Doxyfile
DOXYWIZARD = ./../doc/doxygen/doxywizard
BROWSER = Konqueror
DOCROOT = ./../doc/html/
DOCINDEX = $(DOCROOT)index.html
OBJ = $(DIROBJ)main.o $(DIROBJ)HardWareCore.o
all: $(OBJ)
@echo "==> Haciendo el link de los objetos"
$(C++) $(OBJ) -lpthread -static -o $(SALIDA)
@echo "==> Para copiar utilize (make copy)"
clean: $(OBJ)
@clear
@echo "==> Limpiando objetos"
@$(DEL) $(OBJ)
copy: $(SALIDA)
cp $(SALIDA) C:/
cleanbackup: $(DIRINC)*~ $(DIRCOD)*~
@$(DEL) $(DIRINC)*~
@$(DEL) $(DIRCOD)*~
uninstall: $(SALIDA) $(OBJ)
@clear
@echo "==> Desinstalando todo"
@$(DEL) $(DOCROOT)*
@$(DEL) $(SALIDA)
@$(DEL) $(OBJ)
doc:
@echo "==> Generando la documentacion con Doxygen"
@$(DOXYGEN) $(DOXYFILE)
@clear
#@echo "==> Iniciando el navegador de KDE"
#@$(BROWSER) $(DOCINDEX)&
$(DIROBJ):
@mkdir $(DIROBJ)
$(DIROBJ)HardWareCore.o: $(DIROBJ) $(DIRCOD)HardWareCore.cpp $(DIRINC)HardWareCore.h
$(C++) $(FLAGS) $(DIRCOD)HardWareCore.cpp -o $(DIROBJ)HardWareCore.o
$(DIROBJ)main.o: $(DIROBJ) $(DIRCOD)main.cpp
$(C++) $(DIRCOD)main.cpp -o $(DIROBJ)main.o $(FLAGS)
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.