› Foros › Retro y descatalogado › Consolas clásicas
sdcc -c -mz80 --constseg BANK2 grupo1.c
sdcc -c -mz80 --constseg BANK3 grupo2.c
sdcc -c -mz80 --constseg BANK4 grupo3.c
sdcc -o output.ihx -mz80 --no-std-crt0 --data-loc 0xC000 -Wl-b_BANK2=0x8000 -Wl-b_BANK3=0x8000 -Wl-b_BANK4=0x8000 crt0_sms.rel main.rel SMSlib.lib .\PSGlib.rel .\grupo1.rel .\grupo2.rel .\grupo3.rel
SMS_mapROMBank(2);
SMS_loadTiles(Fase1Tiles_bin, currentVRAMPosTilemap,
Fase1Tiles_bin_size); /
SMS_mapROMBank(4);
PSGPlay(level1_psg); /
SMS_mapROMBank(3);
SMS_loadTiles(Fase3Tiles_bin, currentVRAMPosTilemap,
Fase3Tiles_bin_size); /
kusfo79 escribió:Vale, pues te explico como hacerlo con folder2c, la otra la usaré para la nueva lección con las novedades en la librería.
Bueno, el tema este de los bancos pasa por que la master del cartucho solo ve 48kb. Esto es así por que solo direcciona 64k, que se reparten entre 48kb para la ROM, y la ram de 8 kb está dos veces mapeada seguida. Como 48kb dan para poco, se usaron mappers especiales que eran capaces de cambiar al "vuelo" bloques de 16kb que llamamos "bancos".
El espacio de los 0kb a los 16kb es el Bank 0, el de los 16kb a los 32kb el Bank 1, y el de los 32kb a los 48kb, el Bank 2. DevKitSMS permite cambiar al vuelo el Bank2 con unas simples instrucciones. Vamos a ver como hacerlo:
Lo principal, es que hemos de decidir como agrupamos los assets del juego, de manera que cada grupo no pese más de 16kb, y que cada uno de estos grupos esté en su propio directorio que tratamos con folder2c. Imaginemos un juego de matamarcianos, podriamos agrupar sus assets de la siguiente manera:
grupo1: fondos de la fase 1 & 2
grupo2: fondos de la fase 3&4
grupo3: Musica.
Lo que haríamos sería poner todos los fondos de las fases 1 y 2 en un directorio grupo1, las de las fases 3 y 4 en un directorio grupo2, y en un directorio grupo3, las músicas. Cada uno de estos directorios, al pasar la utilidad folder2.c, nos darà unos ficheros grupo1.h, grupo1.c, grupo2.h, grupo2.c, grupo3.h, grupo3.c
A la hora de compilarlos, ponemos lo siguiente:sdcc -c -mz80 --constseg BANK2 grupo1.c
sdcc -c -mz80 --constseg BANK3 grupo2.c
sdcc -c -mz80 --constseg BANK4 grupo3.c
Las constantes BANKx nos dicen que identificador de banco le vamos a dar (se han de empezar a usar a partir del BANK2, que es el que puede ser cambiado al vuelo).
Luego al linkar, hemos de poner:sdcc -o output.ihx -mz80 --no-std-crt0 --data-loc 0xC000 -Wl-b_BANK2=0x8000 -Wl-b_BANK3=0x8000 -Wl-b_BANK4=0x8000 crt0_sms.rel main.rel SMSlib.lib .\PSGlib.rel .\grupo1.rel .\grupo2.rel .\grupo3.rel
Definiendo la localización de los bancos creados.
Ahora, durante el juego, supongamos que queremos cargar los fondos de la fase1, haríamos:SMS_mapROMBank(2);
SMS_loadTiles(Fase1Tiles_bin, currentVRAMPosTilemap,
Fase1Tiles_bin_size); /
En el momento de ejcutar una música haríamos:SMS_mapROMBank(4);
PSGPlay(level1_psg); /
Y cuando quisieramos cargar los fondos de la fase 3:SMS_mapROMBank(3);
SMS_loadTiles(Fase3Tiles_bin, currentVRAMPosTilemap,
Fase3Tiles_bin_size); /
Obviamente, no hace falta llamar siempre a mapRomBank, solo cuando cambiamos de banco, pero depende de como sea nuestra lógica, esto puede ser mas o menos complicado.
@Gammenon Ha sido una explicación bastante rápida, pero a ver si se entiende
kusfo79 escribió:@Gammenon
Si!, esto es para poder ejecutar la rom en maquinas con Bios (La master americana o la europea), necesitas que haya un header de sega allí. Esto se hace poniendo esto al final de tu fichero principal, fuera de bucles y de todo:
SMS_EMBED_SEGA_ROM_HEADER(productCode,revision);
SMS_EMBED_SDSC_HEADER_AUTO_DATE(verMaj,verMin,author,name,descr);
con tu numero de producto (yo le pongo 99999), la revision. El major version, minversion, autor, nombre de juego y descripcion.
kusfo79 escribió:Buenas!
Pues para los número aleatorios, uso una estrategia bastante tonta. Tengo en ROM una tabla de 256 elementos, llena de números aleatorios (los genero con un script de python). Para escoger un número aleatorio, depende de lo que hago, es por ejemplo, tener una variable de tipo unsigned char que es el indice de número aleatorio, incrementarla a cada frame, y cuando necesito un número aleatorio, coger el elemento del indice actual dentro de la tabla. O también puedes setear este indice inicial cuando por ejemplo el jugador pulsa un boton, y simplemente irlo incrementando cada vez que pides un nuevo valor aleatorio.
Sobre MemSet y Memcopy, hay implementaciones directamente en SDCC, pero no he probado que tal están de optimización. Aquí hay varias optimizaciones del z80:
http://www.smspower.org/Development/Z80ProgrammingTechniques
Por curiosidad, estas usando memoria dinamica? ojo que en estas máquinas con 8kb, todo esto es bastante peligroso
void SMS_isr (void) __interrupt __naked {
__asm
push af
push hl
in a,(_VDPStatusPort) ; also aknowledge interrupt at VDP
ld (_SMS_VDPFlags),a ; write flags to SMS_VDPFlags variable
rlca
jr nc,1$
ld hl,#_VDPBlank ; frame interrupt
ld (hl),#0x01
ld hl,(_KeysStatus)
ld (_PreviousKeysStatus),hl
in a,(_IOPortL)
cpl
ld hl,#_KeysStatus
ld (hl),a
#ifdef TARGET_GG
in a,(_GGIOPort)
#else
in a,(_IOPortH)
#endif
cpl
inc hl
ld (hl),a
jr 2$
1$: ; line interrupt
push bc
push de
push iy
ld hl,(_SMS_theLineInterruptHandler)
call ___sdcc_call_hl
pop iy
pop de
pop bc
2$:
pop hl
pop af ; Z80 disable the interrupts on ISR,
ei ; so we should re-enable them explicitly.
reti ; this is here because function is __naked
__endasm;
}
kusfo79 escribió:Un ejemplo del propio smslib.cvoid SMS_isr (void) __interrupt __naked {
__asm
push af
push hl
in a,(_VDPStatusPort) ; also aknowledge interrupt at VDP
ld (_SMS_VDPFlags),a ; write flags to SMS_VDPFlags variable
rlca
jr nc,1$
ld hl,#_VDPBlank ; frame interrupt
ld (hl),#0x01
ld hl,(_KeysStatus)
ld (_PreviousKeysStatus),hl
in a,(_IOPortL)
cpl
ld hl,#_KeysStatus
ld (hl),a
#ifdef TARGET_GG
in a,(_GGIOPort)
#else
in a,(_IOPortH)
#endif
cpl
inc hl
ld (hl),a
jr 2$
1$: ; line interrupt
push bc
push de
push iy
ld hl,(_SMS_theLineInterruptHandler)
call ___sdcc_call_hl
pop iy
pop de
pop bc
2$:
pop hl
pop af ; Z80 disable the interrupts on ISR,
ei ; so we should re-enable them explicitly.
reti ; this is here because function is __naked
__endasm;
}
typedef struct {
character *characterData;
unsigned char entityIndex;
unsigned char px;
unsigned char py;
unsigned char direction;
unsigned char currentAnimation;
unsigned char currentFrame;
unsigned char framecnt;
unsigned int vramposition;
bool has2ReloadTiles;
bool animationEnded;
} entity;
entity entities[MAX_NUM_ENTITIES];
kusfo79 escribió:@Gammenon
Perdon por no contestar ayer, pero es que las preguntas que me haces requieren una respuesta no pequeña, jajajaja.
El tema del stack overflow, como comentas, pasa especialmente cuando llamas recursivamente a una función con parámetros. Siendo un columns el juego que estás desarrollando, me puedo imaginar que son llamadas que realizas para ver si tienes 3 piezas adyacentes o algo así, no?
Una primera manera de evitar esto, es de pasar de la recursividad y del backtracking, y realizar esa lógica a base de loops, es menos "limpio", pero irá mejor en una master.
Por otro lado, acerca de lo las variables globales, es bastante putilla, especialmente si quieres que sea flexible. Por ejemplo, una manera es crear una seria de variables a,e,i,o,u como unsigned chars, otras b,c,d,f,g como unsigned ints, etc, e irlas reusando dependiendo de la lógica que estás implementando en cada momento. Luego aparte, suelo tener structs con los datos de "entidades", que tienen x,y, vx, vy, etc y los coloco en un array, algo del tipo:typedef struct {
character *characterData;
unsigned char entityIndex;
unsigned char px;
unsigned char py;
unsigned char direction;
unsigned char currentAnimation;
unsigned char currentFrame;
unsigned char framecnt;
unsigned int vramposition;
bool has2ReloadTiles;
bool animationEnded;
} entity;
entity entities[MAX_NUM_ENTITIES];
Y esto lo voy reusando independientemente del tipo de jugabilidad que hay en cada momento. Pero bueno, el ejemplo que pones tu es especialmente peliagudo, jejej.
kusfo79 escribió:@Gammenon
Pues por esto que dices no debería petar la pila...vamos, no me parece que tengas muchos contextos almacenados a la vez en esa situación...
Gammenon escribió:La de cosas que descubre uno al programar. Mucho ojo con estas cosas (sacado del manual de SDCC):
--fsigned-char By default char is unsigned. To set the signess for characters to signed, use the option --fsignedchar.
If this option is set and no signedness keyword (unsigned/signed) is given, a char will be unsigned.
All other types are unaffected
void lineInterruptHandler(void)
{
SMS_setBGScrollX(offsetPointer++);
}
void main() {
SMS_setLineInterruptHandler(&lineInterruptHandler);
SMS_setLineCounter(0);
SMS_enableLineInterrupt();
while (1)
{
SMS_waitForVBlank();
// calculate new values for the offset Array here, reset offsetPointer to &offArray[1]
do_your_math();
offsetPointer=&offArray[1];
// set uppermost line value
SMS_setBGScrollX(offArray[0]);
}
}
SMS_VDPturnOnFeature (VDPFEATURE_LEFTCOLBLANK);
push bc
push de
push iy
ld hl, (_RAM_C020_)
call _LABEL_143A_
pop iy
pop de
pop bc
pop hl
pop af
ei
reti
_LABEL_143A_:
jp hl
ld hl, (_RAM_C011_)
ld c, (hl)
ld iy, _RAM_C011_
inc (iy+0)
jr nz, _LABEL_382_
inc (iy+1)
_LABEL_382_:
ld l, c
jp _LABEL_121A_
_LABEL_121A_:
di
ld a, l
out (Port_VDPAdress), a
ld a, $88
out (Port_VDPAdress), a
ei
ret
push iy
ld hl, (_RAM_C011_)
ld c, (hl)
ld iy, _RAM_C011_
inc (iy+0)
jr nz, _LABEL_382_
inc (iy+1)
_LABEL_382_:
out (Port_VDPAdress), c
ld c, $88
out (Port_VDPAdress), c
pop iy
pop hl
pop af
ei
ret
Baw escribió:Muchas gracias @Gammenon , tu port si que tiene buena pinta. Si le añadimos el Italia 90, tenemos el megagames I portado a Master .
push bc
push de
push iy
ld hl, (_RAM_C020_)
call _LABEL_143A_
pop iy
pop de
pop bc
pop hl
pop af
ei
reti
_LABEL_143A_:
jp hl
;SALTO A POSICION DE MEMORIA _RAM_C020_
ld hl, (_RAM_C011_)
ld c, (hl)
ld iy, _RAM_C011_
inc (iy+0)
jr nz, _LABEL_382_
inc (iy+1)
_LABEL_382_:
ld l, c
jp _LABEL_121A_
_LABEL_121A_:
di
ld a, l
out (Port_VDPAdress), a
ld a, $88
out (Port_VDPAdress), a
ei
ret
ld hl, (_RAM_C020_) -> 16 ciclos
call _LABEL_143A_ -> 17 ciclos
jp hl -> 4 ciclos
jp _LABEL_121A_ -> 10 ciclos
push af
push bc
push de
push iy
ld hl, (_RAM_C011_)
ld c, (hl)
ld iy, _RAM_C011_
inc (iy+0)
jr nz, _LABEL_382_
inc (iy+1)
_LABEL_382_:
ld l, c
di
ld a, l
out (Port_VDPAdress), a
ld a, $88
out (Port_VDPAdress), a
pop iy
pop de
pop bc
pop hl
pop af
ei
reti
ld iy, _RAM_C011_ -> 14 ciclos
inc (iy+0) -> 23 ciclos
jr nz, _LABEL_382_
inc (iy+1) -> 23 ciclos
ld hl, _RAM_C011_ -> 10 ciclos
inc (hl) -> 11 ciclos
jr nz, _LABEL_382_
inc (hl) -> 11 ciclos
inc (hl) -> 11 ciclos
push af -> 11 ciclos
push bc-> 11 ciclos
push de-> 11 ciclos
ex af, af' -> 4 ciclos
exx -> 4 ciclos
pop de -> 10 ciclos
pop bc-> 10 ciclos
pop hl-> 10 ciclos
pop af-> 10 ciclos
ex af, af' -> 4 ciclos
exx -> 4 ciclos
di
exx
ex af, af'
ld hl, (_RAM_C011_)
ld a, (hl)
ld hl,_RAM_C011_
inc (hl)
jr nz, _LABEL_4001_
inc (hl)
inc (hl)
_LABEL_4001_:
out (Port_VDPAddress), a
ld a, $88
out (Port_VDPAddress), a
exx
ex af, af'
ei
ret
kusfo79 escribió:@Baw
Pues aunque no lo hemos visto en movimiento, tu carretera tiene una pinta genial!
Si te da tiempo a tener algo medio hecho, podrías presentarte a la SMSPower competition que acaba el dia 21!
http://www.smspower.org/forums/16959-Competitions2018DiscussionThread
Baw escribió:Muchas gracias!
no llego al día 21 , lo tengo que dejar aparcado unos días y me queda bastante trabajo todavía.
Tengo que conseguir crear la curvas de manera suave y con sentido porque ahora puedo interpolar de la recta a la curva pero queda un poco raro (creo que ya tengo todas las variables para hacerlo bien). También tengo que añadir un desplazamiento constante a todas las líneas, pero variable entre frames, para que cuando la carretera se gire la parte más cercana a la cámara no se deforme y se quede centrada.
Por último y con lo que he estado la última vez que me he puesto es con los cambios de paleta tanto entre líneas, como en mitad de la línea. Necesito tiempo para hacer pruebas y para ver si puedo integrarlo. Así puedo ir haciendo cambios de color de algunas cosas sobre el background (que se come 12 colores para las 3 animaciones de la carretera) y dejar la paleta de sprites tranquila para las motos y elementos laterales del escenario. Tengo el estudio hecho sobre los cambios de colores que necesito y cuando los necesito y en la teoría todo es posible
Bueno el cambio de color a mitad de línea (que me vendría genial para colorear los marcadores de rojo a la izquierda y de verde a la derecha) lo veo poco posible. He estado haciendo pruebas y de momento no consigo que siempre empiece en el mismo sitio el cambio de color, ni que siempre tarde lo mismo (y no se si el emulador se lo comerá bien en las pruebas o si funcionará diferente en una master real).
Byte unaFuncion()
{
return 5;
}
miArray[0] = unaFuncion();
Baw escribió:@Gammenon pfff...complicado, quizá con algo más de código (como lo pintas, como esta declarado ese array, etc).
¿Usas base octal para algo? (¿se puede usar?). Lo único que se me ocurre es que 65 decimal es 101 en octal y 5 es 101 en binario .
Baw escribió:@Gammenon pfff...complicado, quizá con algo más de código (como lo pintas, como esta declarado ese array, etc).
¿Usas base octal para algo? (¿se puede usar?). Lo único que se me ocurre es que 65 decimal es 101 en octal y 5 es 101 en binario .
EDITO (Otra idea):
65 decimal es 0100 0001 en binario. Si estas trabajando a nivel de bits, con desplazamientos, mascaras,etc y si ese cinco se calcula como la suma de 4 + 1 (mucha casualidad). Puedes llegar a 65 si has desplazado sin querer los bits del número 4 antes de sumar.
Gammenon escribió:Es algo así de memoria:
typedef unsigned char Byte;
Byte miArray[3];
wave escribió:Gammenon escribió:Es algo así de memoria:
typedef unsigned char Byte;
Byte miArray[3];
Como estás mirando el valor?
Los typedef son una pesadilla, recomiendo no usarlos.Gammenon escribió:Es algo así de memoria:
typedef unsigned char Byte;
Byte miArray[3];
Manveru Ainu escribió:Los typedef son una pesadilla, recomiendo no usarlos.Gammenon escribió:Es algo así de memoria:
typedef unsigned char Byte;
Byte miArray[3];
Aparte de eso y desde el desconocimiento, me imagino que en una máquina de 8 bits no es problema y que leerá los words como 2 bytes y no pasa nada, pero lo comento por si acaso porque en micros como el 68k con alineamiento a word, eso de tener un array de bytes de tamaño impar puede petar en cualquier momento.