Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
3143 lines (2096 sloc) 79.2 KB
/*
ZEsarUX ZX Second-Emulator And Released for UniX
Copyright (C) 2013 Cesar Hernandez Bano
This file is part of ZEsarUX.
ZEsarUX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include "cpu.h"
#include "tsconf.h"
#include "mem128.h"
#include "debug.h"
#include "contend.h"
#include "menu.h"
#include "screen.h"
#include "ula.h"
#include "operaciones.h"
#include "zxevo.h"
//temporal para printf debug que mira contador_segundo
#include "timer.h"
void tsconf_generate_im1_im2(z80_byte vector);
//z80_byte tsconf_last_port_eff7;
//z80_byte tsconf_last_port_dff7;
//z80_byte tsconf_nvram[256];
z80_byte tsconf_af_ports[256];
//Si se usa vdac con full 15 bits, o con pwm: en ese caso, cada componente de 5 bits son diferentes hasta valor 24, a partir de ahi son iguales a 255:
/*
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
0, 10, 21, 31, 42, 53, 63, 74, 85, 95, 106, 117, 127, 138, 149, 159, 170, 181, 191, 202, 213, 223, 234, 245, 255,
Y a partir de 24 todos son 255
*/
//Por defecto con pwm. Unreal emulator lo tendra asi (los colores son iguales que sin vdac), por lo que entiendo que es lo normal
z80_bit tsconf_vdac_with_pwm={1};
/*
Poner 3 modos de color:
Rgb 6 (2 bits por componente)
O
Con vdac, rango de 0-31 por componente o 0-24 (el mismo setting que hasta ahora)
256 color cells, 16 bit each.
bit 15 (0x8000) is used to distinct the old 0-24 PWM and linear RGB5.
When bit15=0 then values 0-24 are linear grayscale and values 24-31 are reproduced as 255 on output.
When bit15=1 then values 0-31 are linear grayscale.
RGB5 to RGB8 is a tricky convertion, but formulas used are as simple as possible.
*/
z80_byte tsconf_palette_depth=5;
z80_byte tsconf_fmaps[TSCONF_FMAPS_SIZE];
/*
Offset A[11:8] RAM Description
#000 000x CRAM Color Palette RAM, 256 cells 16 bit wide, 16 bit access
#200 001x SFILE Sprite Descriptors, 85 cells 48 bit wide, 16 bit access
#400 0100 REGS TS-Conf Registers, 8 bit access, adressing is the same as by #nnAF port
*/
void tsconf_write_fmaps(int tsconf_fmaps_offset,z80_byte valor) {
if (tsconf_fmaps_offset<0x200) {
//printf ("Zona tsconf cram\n");
tsconf_fmaps[tsconf_fmaps_offset]=valor;
}
if (tsconf_fmaps_offset>=0x200 && tsconf_fmaps_offset<0x400) {
//printf ("Zona tsconf sprites\n");
tsconf_fmaps[tsconf_fmaps_offset]=valor;
}
if (tsconf_fmaps_offset>=0x400 && tsconf_fmaps_offset<0x500) {
//printf ("Zona tsconf registers\n");
//Solo escribe en regustro tsconf. no en ram fmaps
tsconf_write_af_port(tsconf_fmaps_offset-0x400,valor);
}
}
//Retorna valor entre 0...32767, segun color de entrada entre 0..255
z80_int tsconf_return_cram_color(z80_byte color)
{
int offset=color*2;
z80_byte color_l=tsconf_fmaps[offset];
z80_byte color_h=tsconf_fmaps[offset+1]&127;
z80_int color_retorno=(color_h<<8)|color_l;
return color_retorno;
}
z80_byte tsconf_return_cram_palette_offset(void)
{
return (tsconf_af_ports[7]&0xF)*16;
}
//Direcciones donde estan cada pagina de rom. 32 paginas de 16 kb
z80_byte *tsconf_rom_mem_table[32];
//Direcciones donde estan cada pagina de ram, en paginas de 16 kb
z80_byte *tsconf_ram_mem_table[256];
//Direcciones actuales mapeadas, bloques de 16 kb
z80_byte *tsconf_memory_paged[4];
//En teoria esto se activa cuando hay traps tr-dos
z80_bit tsconf_dos_signal={0};
//Almacena tamanyo pantalla y border para modo actual
//Los inicializamos con algo por si acaso
//Border indica la mitad del total, o sea, si dice 40, es margen izquierdo 40 y margen derecho 40
int tsconf_current_pixel_width=256;
int tsconf_current_pixel_height=192;
int tsconf_current_border_width=0;
int tsconf_current_border_height=0;
char *tsconf_video_modes_array[]={
"ZX",
"16c",
"256c",
"Text"
};
char *tsconf_video_sizes_array[]={
"256x192",
"320x200",
"320x240",
"360x288"
};
//z80_bit tsconf_fired_frame_interrupt={0};
#define TSCONF_SCANLINE_TRANSPARENT_COLOR 65535
//32768 colores maximo. Tenemos array de z80_int (16 bits). color 65535 es transparente
//360 pixeles de ancho maximo (720 en modo texto)
//Pero coordenadas sprites pueden ir de 0 a 511, teniendo en cuenta que ocupan x2 de ancho, pues son 1024
//sumamos tambien +8 porque los tiles empiezan en posicion 8 y tienen esos 8 primeros de margen por la izquierda
//Le damos mas margen por si acaso
#define TSCONF_MAX_WIDTH_LAYER (1024+8+256)
z80_int tsconf_layer_ula[TSCONF_MAX_WIDTH_LAYER];
z80_int tsconf_layer_tiles_zero[TSCONF_MAX_WIDTH_LAYER];
z80_int tsconf_layer_tiles_one[TSCONF_MAX_WIDTH_LAYER];
z80_int tsconf_layer_sprites_zero[TSCONF_MAX_WIDTH_LAYER];
z80_int tsconf_layer_sprites_one[TSCONF_MAX_WIDTH_LAYER];
z80_int tsconf_layer_sprites_two[TSCONF_MAX_WIDTH_LAYER];
//Forzar desde menu a desactivar capas
z80_bit tsconf_force_disable_layer_ula={0};
z80_bit tsconf_force_disable_layer_tiles_zero={0};
z80_bit tsconf_force_disable_layer_tiles_one={0};
z80_bit tsconf_force_disable_layer_sprites_zero={0};
z80_bit tsconf_force_disable_layer_sprites_one={0};
z80_bit tsconf_force_disable_layer_sprites_two={0};
z80_bit tsconf_force_disable_layer_border={0};
//Prueba ny17: Todo activado: 71-73 %
//Sin ula: 66%
//Sin sprites: 70%
//Sin tiles_zero: 65%
//Sin tiles_one: 69%
//sin ninguna capa: 58%
//Si se hace render de sprites y tiles usando funcion rapida de renderizado
//z80_bit tsconf_si_render_spritetile_rapido={0};
z80_byte tsconf_get_video_mode_display(void)
{
/*
Modos de video:
0 ZX
1 16c.
Bits are index to CRAM, where PalSel.GPAL is 4 MSBs and the pixel are 4 LSBs of the index.
Pixels are bits7..4 - left, bits3..0 - right.
Each line address is aligned to 256.
GXOffs and GYOffs add offset to X and Y start address in pixels.
2 256c.
Bits 7..0 are index to CRAM.
Each line address is aligned to 512.
GXOffs and GYOffs add offset to X and Y start address in pixels.
3 text
*/
return (tsconf_af_ports[0]&3);
}
z80_byte tsconf_get_video_size_display(void)
{
return ((tsconf_af_ports[0]>>6)&3);
}
//Actualiza valores de variables de tamanyo pantalla segun modo de video actual
//Modo de video ZX Spectrum solo tiene sentido con resolucion 256x192
void tsconf_set_sizes_display(void)
{
z80_byte videosize=tsconf_get_video_size_display();
/*
00 - 256x192: border size: 104x96
01 - 320x200: border size: 40x88
10 - 320x240: border size: 40x48
11 - 360x288: border size: 0x0
*/
switch (videosize) {
case 0:
tsconf_current_pixel_width=256;
tsconf_current_pixel_height=192;
break;
case 1:
tsconf_current_pixel_width=320;
tsconf_current_pixel_height=200;
break;
case 2:
tsconf_current_pixel_width=320;
tsconf_current_pixel_height=240;
break;
case 3:
tsconf_current_pixel_width=360;
tsconf_current_pixel_height=288;
break;
}
tsconf_current_border_width=(360-tsconf_current_pixel_width)/2;
tsconf_current_border_height=(288-tsconf_current_pixel_height)/2;
//printf ("Current video size. Pixel size: %dX%d Border size: %dX%d\n",
// tsconf_current_pixel_width,tsconf_current_pixel_height,tsconf_current_border_width*2,tsconf_current_border_height*2);
}
void tsconf_get_current_video_mode(char *s)
{
sprintf (s,"%s, %s",
tsconf_video_sizes_array[tsconf_get_video_size_display()],
tsconf_video_modes_array[tsconf_get_video_mode_display()]
);
}
void tsconf_splash_video_size_mode_change(void)
{
char buffer_mensaje[64];
char buffer_mensaje2[64];
/*sprintf (buffer_mensaje,"Setting video mode %s, size %s",
tsconf_video_modes_array[tsconf_get_video_mode_display()],tsconf_video_sizes_array[tsconf_get_video_size_display()]);*/
tsconf_get_current_video_mode(buffer_mensaje2);
sprintf (buffer_mensaje,"Setting video mode %s",buffer_mensaje2);
screen_print_splash_text(10,ESTILO_GUI_TINTA_NORMAL,ESTILO_GUI_PAPEL_NORMAL,buffer_mensaje);
}
void tsconf_set_emulator_setting_turbo(void)
{
/*
Register 32
bits 1-0:
00: 3.5 mhz
01: 7
10: 14
11: reserved
*/
z80_byte t=tsconf_af_ports[32] & 3;
if (t==0) cpu_turbo_speed=1;
else if (t==1) cpu_turbo_speed=2;
else cpu_turbo_speed=4;
//printf ("Setting turbo: %d\n",cpu_turbo_speed);
cpu_set_turbo_speed();
}
void tsconf_fire_dma_interrupt(void)
{
//Depende de DI???
if (iff1.v==0) return;
//registro intmask 2aH bit 2
if ((tsconf_af_ports[0x2a]&4)==0) return;
tsconf_generate_im1_im2(0xFB);
}
//Retorna direccion lineal dma en base a los 3 registros por separado
int tsconf_return_dma_addr_reg_to_linear(z80_byte bajo,z80_byte medio,z80_byte alto)
{
//printf ("%d %d %d\n",bajo,medio,alto);
int f_bajo=bajo&254; //Descartar bit bajo
int f_medio=medio&63; //Descartar los dos bits altos
int f_alto=alto;
f_medio=f_medio<<8;
f_alto=f_alto<<14;
int final=f_bajo | f_medio | f_alto;
//printf ("%d\n",final);
return final;
}
//Funcion contraria a la anterior, para una direccion lineal dma dada, retorna los 3 registros por separado
void tsconf_return_dma_addr_linear_to_reg(int addr,z80_byte *bajo,z80_byte *medio,z80_byte *alto)
{
*bajo=addr & 254;
addr >>=8;
*medio=addr & 63;
addr >>=6;
*alto=addr;
}
int tsconf_align_address(int orig_destination,int destination,int addr_align_size)
{
int lower;
if (addr_align_size) { //1 alinear a 512
//printf ("alinear a 512\n");
lower=orig_destination&0x1FF;
destination=destination&0xFFFE00;
destination |=lower;
destination +=512;
}
else { //0 alinear a 256
//printf ("alinear a 256\n");
lower=orig_destination&0xFF;
destination=destination&0xFFFF00;
destination |=lower;
destination +=256;
}
return destination;
}
/*int tsconf_align_address_prueba(int orig_destination,int destination,int addr_align_size)
{
int lower;
if (addr_align_size) { //1 alinear a 512
//printf ("alinear a 512\n");
//lower=orig_destination&0x1FF;
destination=destination&0xFFFE00;
//destination |=lower;
destination +=512;
}
else { //0 alinear a 256
//printf ("alinear a 256\n");
//lower=orig_destination&0xFF;
destination=destination&0xFFFF00;
//destination |=lower;
destination +=256;
}
return destination;
}*/
int debug_tsconf_dma_source=0;
int debug_tsconf_dma_destination=0;
int debug_tsconf_dma_burst_length=0;
int debug_tsconf_dma_burst_number=0;
z80_byte debug_tsconf_dma_s_align=0;
z80_byte debug_tsconf_dma_d_align=0;
z80_byte debug_tsconf_dma_addr_align_size=0;
z80_byte debug_tsconf_dma_ddev=0;
z80_byte debug_tsconf_dma_rw=0;
z80_bit tsconf_dma_disabled={0};
void tsconf_dma_put_pixel_blit2(z80_byte *destination, z80_byte byte_source, z80_byte addr_align_size,z80_byte dma_opt)
{
//addr_align_size: 0 4bpp. 1 8bb
z80_byte byte_destino=*destination;
if (addr_align_size) {
//8 bpp
//blit.b0 = (((d0.b0 + d1.b0) > 0xFF) && sat) ? 0xFF : (d0.b0 + d1.b0);
byte_destino=(((byte_destino + byte_source) > 0xFF) && dma_opt) ? 0xFF : (byte_destino + byte_source);
}
else {
//4 bpp
z80_byte nibble_destino_alto,nibble_destino_bajo;
z80_byte nibble_source_alto,nibble_source_bajo;
nibble_destino_alto=(byte_destino>>4)&0xF;
nibble_destino_bajo=(byte_destino)&0xF;
nibble_source_alto=(byte_source>>4)&0xF;
nibble_source_bajo=(byte_source)&0xF;
nibble_destino_alto = (((nibble_destino_alto + nibble_source_alto) > 0xF) && dma_opt) ? 0xF : (nibble_destino_alto + nibble_source_alto);
nibble_destino_bajo = (((nibble_destino_bajo + nibble_source_bajo) > 0xF) && dma_opt) ? 0xF : (nibble_destino_bajo + nibble_source_bajo);
byte_destino=(nibble_destino_alto<<4)|nibble_destino_bajo;
}
*destination=byte_destino;
}
void tsconf_dma_put_pixel_ifnotzero(z80_byte *destination, z80_byte source, z80_byte addr_align_size)
{
//addr_align_size: 0 4bpp. 1 8bb
//8 bpp
if (addr_align_size) {
if (source) *destination=source;
}
else {
z80_byte byte_destino=*destination;
//4 bpp
z80_byte nibble=source & 0xF0;
if (nibble) {
byte_destino &=0x0F;
byte_destino |=nibble;
}
nibble=source & 0x0F;
if (nibble) {
byte_destino &=0xF0;
byte_destino |=nibble;
}
*destination=byte_destino;
}
}
//burst_length esta en words
void tsconf_dma_operation(int source,int destination,int burst_length,int burst_number,z80_byte s_align,z80_byte d_align,z80_byte addr_align_size,z80_byte dma_ddev,z80_byte dma_rw,z80_byte dma_opt)
{
int orig_source;
int orig_destination;
int source_mask,destination_mask;
z80_byte *source_pointer;
z80_byte *destination_pointer;
//Guardamos estos valores en variable de debug para mostrarlos en menu debug, solo a titulo informativo
debug_tsconf_dma_source=source;
debug_tsconf_dma_destination=destination;
debug_tsconf_dma_burst_length=burst_length;
debug_tsconf_dma_burst_number=burst_number;
debug_tsconf_dma_s_align=s_align;
debug_tsconf_dma_d_align=d_align;
debug_tsconf_dma_addr_align_size=addr_align_size;
debug_tsconf_dma_ddev=dma_ddev;
debug_tsconf_dma_rw=dma_rw;
z80_byte dma_operation=dma_ddev*2+dma_rw;
//debug_printf (VERBOSE_DEBUG,"DMA operation type: %s",tsconf_dma_types[dma_operation]);
//switch (dma_ddev) {
switch (dma_operation) {
case 2:
//printf ("RAM (Src) is copied to RAM (Dst)\n");
source_pointer=tsconf_ram_mem_table[0];
destination_pointer=tsconf_ram_mem_table[0];
source_mask=destination_mask=0x3FFFFF; //4 mb
break;
case 3:
//printf ("Pixels from RAM (Src) are copied to RAM (Dst) if they non zero. addr_align_size: %d\n",addr_align_size);
source_pointer=tsconf_ram_mem_table[0];
destination_pointer=tsconf_ram_mem_table[0];
source_mask=destination_mask=0x3FFFFF; //4 mb
break;
case 8:
//printf ("RAM (Dst) is filled with word from RAM (Src)\n");
source_pointer=tsconf_ram_mem_table[0];
destination_pointer=tsconf_ram_mem_table[0];
source_mask=destination_mask=0x3FFFFF; //4 mb
break;
case 9:
//printf ("RAM (Src) is copied to CRAM (Dst)\n");
source_pointer=tsconf_ram_mem_table[0];
destination_pointer=tsconf_fmaps;
source_mask=0x3FFFFF; //4 mb
destination_mask=0x1FF; //512 bytes
break;
case 11:
//printf ("RAM (Src) is copied to SFILE (Dst)\n"); //Digger usa esto
source_pointer=tsconf_ram_mem_table[0];
destination_pointer=&tsconf_fmaps[0x200];
source_mask=0x3FFFFF; //4 mb
destination_mask=0x1FF; //512 bytes
break;
case 12:
//ldd.spg usa Unemulated dma type: rw: 0 ddev: 06H
//Pixels from RAM (Src) are blitted to RAM (Dst) with adder. De momento hacemos copia tal cual
//printf ("Pixels from RAM (Src) are blitted to RAM (Dst) with adder\n");
source_pointer=tsconf_ram_mem_table[0];
destination_pointer=tsconf_ram_mem_table[0];
source_mask=destination_mask=0x3FFFFF; //4 mb
break;
default:
debug_printf (VERBOSE_ERR,"Unemulated dma type: rw: %d ddev: %02XH",dma_rw,dma_ddev);
return;
break;
}
//Si desactivada la dma, volver
if (tsconf_dma_disabled.v) return;
//Esto creo que no tiene ningún tipo de sentido. El mapeo de fmaps es solo cuando se accede a memoria normalmente entre zona de 64kb
/*if ((tsconf_af_ports[0x15]&16)!=0) {
printf ("----------Posible operacion dma con fmaps activo\n");
//ashot, hny2k16 usan esto
}*/
for (;burst_number>0;burst_number--){
int i;
orig_source=source;
orig_destination=destination;
for (i=0;i<burst_length;i++) {
destination &=destination_mask;
source &=source_mask;
int incremento_destino=0;
int incremento_origen=0;
switch (dma_operation) {
case 2:
//printf ("RAM (Src) is copied to RAM (Dst)\n");
destination_pointer[destination]=source_pointer[source];
destination_pointer[destination+1]=source_pointer[source+1];
//destination +=2;
//source +=2;
incremento_destino=incremento_origen=2;
break;
case 3:
//printf ("Pixels from RAM (Src) are copied to RAM (Dst) if they non zero. addr_align_size: %d\n",addr_align_size);
//edge_grinder usa esto
tsconf_dma_put_pixel_ifnotzero(&destination_pointer[destination],source_pointer[source],addr_align_size);
tsconf_dma_put_pixel_ifnotzero(&destination_pointer[destination+1],source_pointer[source+1],addr_align_size);
//destination +=2;
//source +=2;
incremento_destino=incremento_origen=2;
break;
case 8:
//printf ("RAM (Dst) is filled with word from RAM (Src)\n");
destination_pointer[destination]=source_pointer[source];
destination_pointer[destination+1]=source_pointer[source+1];
//destination +=2;
incremento_destino=2;
break;
case 9:
//printf ("RAM (Src) is copied to CRAM (Dst) source %06XH dest %06XH\n",source,destination);
destination_pointer[destination]=source_pointer[source];
destination_pointer[destination+1]=source_pointer[source+1];
//destination +=2;
//source +=2;
incremento_destino=incremento_origen=2;
break;
case 11:
//printf ("RAM (Src) is copied to SFILE (Dst)\n"); //Digger usa esto
destination_pointer[destination]=source_pointer[source];
destination_pointer[destination+1]=source_pointer[source+1];
//destination +=2;
//source +=2;
incremento_destino=incremento_origen=2;
break;
case 12:
//ldd.spg usa Unemulated dma type: rw: 0 ddev: 06H
//Pixels from RAM (Src) are blitted to RAM (Dst) with adder.
//printf ("Pixels from RAM (Src) are blitted to RAM (Dst) with adder\n");
tsconf_dma_put_pixel_blit2(&destination_pointer[destination],source_pointer[source],addr_align_size,dma_opt);
tsconf_dma_put_pixel_blit2(&destination_pointer[destination+1],source_pointer[source+1],addr_align_size,dma_opt);
//destination +=2;
//source +=2;
incremento_destino=incremento_origen=2;
break;
}
//if (i!=burst_length-1) {
destination +=incremento_destino;
source +=incremento_origen;
//}
}
if (d_align) {
destination=tsconf_align_address(orig_destination,destination,addr_align_size);
}
if (s_align) {
source=tsconf_align_address(orig_source,source,addr_align_size);
}
}
//Guardar los registros resultantes source, destination
//debug_printf (VERBOSE_DEBUG,"DMA pointers after DMA operation: source: %06XH destination: %06XH",source,destination);
tsconf_return_dma_addr_linear_to_reg(source,&tsconf_af_ports[0x1a],&tsconf_af_ports[0x1b],&tsconf_af_ports[0x1c]);
tsconf_return_dma_addr_linear_to_reg(destination,&tsconf_af_ports[0x1d],&tsconf_af_ports[0x1e],&tsconf_af_ports[0x1f]);
//Sacar valores solo para debug
//printf ("Writing DMA CTRL. value: %02XH\n",tsconf_af_ports[0x27]);
//int finaldmasource=tsconf_return_dma_addr_reg_to_linear(tsconf_af_ports[0x1a],tsconf_af_ports[0x1b],tsconf_af_ports[0x1c]);
//int finaldmadest=tsconf_return_dma_addr_reg_to_linear(tsconf_af_ports[0x1d],tsconf_af_ports[0x1e],tsconf_af_ports[0x1f]);
//debug_printf (VERBOSE_DEBUG,"DMA pointers after DMA operation and read from registers: source: %06XH destination: %06XH",finaldmasource,finaldmadest);
}
//Max 18
char *tsconf_dma_types[]={
// 01234567890123456789
"(Reserved)", //0
"(Reserved)",
"RAM to RAM",
"Pixels to RAM",
"SPI to RAM",
"RAM to SPI ",
"IDE to RAM",
"RAM to IDE",
"RAM fill from RAM",
"RAM to CRAM",
"FDD dump into RAM", //10
"RAM to SFILE",
// 01234567890123456789
"Pixels to RAM blit", //12
"(Reserved)",
"(Reserved)",
"(Reserved)" //15
};
void tsconf_write_af_port(z80_byte puerto_h,z80_byte value)
{
tsconf_af_ports[puerto_h]=value;
if (puerto_h==0) {
tsconf_splash_video_size_mode_change();
//Cambio vconfig
tsconf_set_sizes_display();
modificado_border.v=1;
}
//temp debug vpage
if (puerto_h==1) {
//printf ("---VPAGE: %02XH\n",puerto_h);
}
if (puerto_h==7) {
//printf ("Palette: %02XH\n",value);
}
//Bit 4 de 32765 es bit 0 de #21AF
if (puerto_h==0x21) {
puerto_32765 &=(255-16); //Reset bit 4
//Si bit 0 de 21af, poner bit 4
if (value&1) puerto_32765|=16;
}
//Port 0x7FFD is an alias of Page3, page3=tsconf_af_ports[0x13];
if (puerto_h==0x13) {
puerto_32765=value;
}
//Gestion fmaps
/*
Vamos a empezar por la carga de la paleta. Para ello, debe habilitar la memoria RAM paleta de mapeo,
incluyendo el puerto FMAddr cuarto bit. En este caso, los bits 0-3 especifica la asignación de dirección
(por ejemplo, 0 - # 0000 8-8000 # 15 - # F000, etc.). Después de encender el mapeo de las direcciones seleccionadas
estarán disponibles para la ventana para cargar paleta. A continuación, utilizando LDIR convencional nos movemos paleta de 512 bytes.
Después de enviar los datos, debe cerrar la ventana de asignación, dejando caer el puerto FMAddr cuarto bit. Considere este ejemplo:
FMAddr EQU #15AF
LOAD_PAL LD A,%00010000 ; Включаем маппинг по адресу #0000
LD BC,FMAddr
OUT (C),A
LD HL,ZXPAL ; Перебрасываем данные (32 байта)
LD DE,#0000
LD BC,#0020
LDIR
XOR A ; Отключаем маппинг
LD BC,FMAddr
OUT (C),A
RET
ZXPAL dw #0000,#0010,#4000,#4010,#0200,#0210,#4200,#4210
dw #0000,#0018,#6000,#6018,#0300,#0318,#6300,#6318
*/
if (puerto_h==0x15) {
//printf ("Registro fmaps 0x15 valor: %02XH\n",value);
}
if (puerto_h==32) {
tsconf_set_emulator_setting_turbo();
}
//if (puerto_h>=0x1A && puerto_h<=0x1F) debug_printf (VERBOSE_DEBUG,"Writing DMA source/dest register %02XH",puerto_h);
if (puerto_h==0x27) {
//Dmactrl
//printf ("Writing DMA CTRL. value: %02XH\n",tsconf_af_ports[0x27]);
int dmasource=tsconf_return_dma_addr_reg_to_linear(tsconf_af_ports[0x1a],tsconf_af_ports[0x1b],tsconf_af_ports[0x1c]);
int dmadest=tsconf_return_dma_addr_reg_to_linear(tsconf_af_ports[0x1d],tsconf_af_ports[0x1e],tsconf_af_ports[0x1f]);
//int dma_burst_length=(tsconf_af_ports[0x26]+1)*2;
int dma_burst_length=tsconf_af_ports[0x26];
dma_burst_length++;
//dma_burst_length*=2; funciona con words
//int dma_num=tsconf_af_ports[0x28]+1;
int dma_num=tsconf_af_ports[0x28];
dma_num++;
//int dma_length=dma_burst_length*dma_num;
//printf ("DMA length: %d x %d = %d\n",dma_burst_length,dma_num,dma_length);
z80_byte dma_ddev=tsconf_af_ports[0x27]&7;
z80_byte dma_a_sz=((tsconf_af_ports[0x27])>>3)&1;
z80_byte dma_d_algn=((tsconf_af_ports[0x27])>>4)&1;
z80_byte dma_s_algn=((tsconf_af_ports[0x27])>>5)&1;
z80_byte dma_opt=((tsconf_af_ports[0x27])>>6)&1;
z80_byte dma_rw=((tsconf_af_ports[0x27])>>7)&1;
//printf ("DMA movement type: ");
//debug_printf (VERBOSE_DEBUG,"Writing DMA DMA source: %06XH dest: %06XH DMALen: %02XH A_SZ: %d D_ALGN: %d S_ALGN: %d DMACtrl: %02XH DMANum: %02XH",
// dmasource,dmadest,tsconf_af_ports[0x26],dma_a_sz,dma_d_algn,dma_s_algn,tsconf_af_ports[0x27],tsconf_af_ports[0x28]);
tsconf_dma_operation(dmasource,dmadest,dma_burst_length,dma_num,dma_s_algn,dma_d_algn,dma_a_sz,dma_ddev,dma_rw,dma_opt);
//void tsconf_dma_operation(int source,int destination,int burst_length,int burst_number,z80_byte s_align,z80_byte d_align,z80_byte addr_align_size,z80_byte dma_ddev,z80_byte dma_rw)
if (tsconf_dma_disabled.v==0) tsconf_fire_dma_interrupt();
}
//Si cambia registro #21AF (memconfig) o page0-3
if (puerto_h==0x21 || puerto_h==0x10 || puerto_h==0x11 || puerto_h==0x12 || puerto_h==0x13 ) tsconf_set_memory_pages();
}
z80_byte tsconf_get_af_port(z80_byte index)
{
//casos especiales
switch(index) {
case 0:
//status
//bit 6: powerup
//bit 5: fdrver (0=regular, 1=fdd ripper)
//bits 0-2: vdac type
/*
000 2-bit VDAC + PWM levels 0-24
001 3-bit VDAC
010 4-bit VDAC
011 5-bit VDAC
100-110 reserved
111 VDAC2 (FT812)
mis opciones:
"without vdac" - 0 (000)
"with vdac" - 3 (011) or 7 (111)
*/
if (tsconf_vdac_with_pwm.v==0) return 7;
else return 0;
break;
//Decimos que la dma siempre ha finalizado operación
case 0x27:
//return tsconf_af_ports[index] & 0x7f; //Quitar bit 7
//Solo se usa bit 7, quitarlos todos
return 0;
break;
}
return tsconf_af_ports[index];
}
void tsconf_reset_cpu(void)
{
tsconf_af_ports[0]=0;
//Bit 4 de 32765 es bit 0 de #21AF. Por tanto poner ese bit 0 a 0
tsconf_af_ports[0x21] &=(255-1);
//puerto_32765 &=(255-16);
//TODO. Que otros puertos de tsconf se ponen a 0 en el reset?
//De momento hacemos que cuando se haga un reset, no se vuelve a la system rom
temp_tsconf_in_system_rom_flag=0;
tsconf_set_memory_pages();
tsconf_set_sizes_display();
}
void tsconf_init_memory_tables(void)
{
debug_printf (VERBOSE_DEBUG,"Initializing TSConf memory pages");
z80_byte *puntero;
puntero=memoria_spectrum;
int i;
for (i=0;i<TSCONF_ROM_PAGES;i++) {
tsconf_rom_mem_table[i]=puntero;
puntero +=16384;
}
for (i=0;i<TSCONF_RAM_PAGES;i++) {
tsconf_ram_mem_table[i]=puntero;
puntero +=16384;
}
//Tablas contend
/*contend_pages_actual[0]=0;
contend_pages_actual[1]=contend_pages_tsconf[5];
contend_pages_actual[2]=contend_pages_tsconf[2];
contend_pages_actual[3]=contend_pages_tsconf[0];*/
}
/*
Memory paging:
af_registers[16] page at 0000 at reset: 0
af_registers[17] page at 4000 at reset: 5
af_registers[18] page at 8000 at reset: 2
af_registers[19] page at c000 at reset: 0
Segmentos 4000 y 8000 siempre determinados por esos 17 y 18
En espacio c000 interviene:
af_registers[19] (page3)
Memconfig=af_register[33]
bits 6,7=lck128
si lck128:
00 512 kb 7ffd[7:6]=page3[4:3]
01 128 kb 7ffd[7:6]=00
10 auto !a[13] ???????
11 1024kb #7FFD[7:6] = Page3[4:3], #7FFD[5] = Page3[5]
*/
z80_byte tsconf_get_memconfig(void)
{
return tsconf_af_ports[0x21];
}
z80_byte tsconf_get_memconfig_lck(void)
{
return (tsconf_get_memconfig()>>6)&3;
}
int temp_tsconf_in_system_rom_flag=1;
int tsconf_in_system_rom(void)
{
if (temp_tsconf_in_system_rom_flag) return 1;
return 0;
//TODO. No entiendo bien cuando entra aqui: 00 - after reset, only in "no map" mode, System ROM, suponemos que solo al encender la maquina,
//cosa que no es cierta
}
z80_byte tsconf_get_rom_bank(void)
{
/*
Mapeo ROM
The following ports/signals are in play:
- #7FFD bit4,
- DOS signal,
- #21AF (Memconfig),
- #10AF (Page0).
Memconfig:
- bit0 is an alias of bit4 #7FFD,
- bit2 selects mapping mode (0 - map, 1 - no map),
- bit3 selects what is in #0000..#3FFF (0 - ROM, 1 - RAM).
In "no map" the page in the win0 (#0000..#3FFF) is set in Page0 directly. 8 bits are used if RAM, 5 lower bits -
if ROM (ROM has 32 pages i.e. 512kB).
In "map" mode Page0 selects ROM page bits 4..2 (which are set to 0 at reset) and bits 1..0 are taken from other sources,
selecting one of four ROM pages, see table.
bit1/0
00 - after reset, only in "no map" mode, System ROM,
01 - when DOS signal active, TR-DOS,
10 - when no DOS and #7FFD.4 = 0 (or Memconfig.0 = 0), Basic 128,
11 - when no DOS and #7FFD.4 = 1 (or Memconfig.0 = 1), Basic 48.
*/
z80_byte memconfig=tsconf_get_memconfig();
if (memconfig & 4) {
//Modo no map
//bit3 selects what is in #0000..#3FFF (0 - ROM, 1 - RAM).
z80_byte banco=tsconf_af_ports[0x10];
return banco;
}
else {
z80_byte banco;
//Modo map
//printf ("paginacion modo map\n");
z80_byte page0=tsconf_af_ports[0x10];
page0=page0&(4+8+16); //In "map" mode Page0 selects ROM page bits 4..2
//TODO. No entiendo bien cuando entra aqui: 00 - after reset, only in "no map" mode, System ROM, suponemos que solo al encender la maquina,
//cosa que no es cierta
if (tsconf_in_system_rom() ) banco=0;
else {
//if (tsconf_dos_signal.v) banco=1;
if (0) banco=1; //mejor no miramos dos_signal y gestionamos el salto de rom mediante el core_nested de betadisk,
//de tal manera que alli se comprueba si salta a tr-dos cuando esta en rom 3 llamando a esta funcion
else {
//printf ("32765 %d memconfig %d\n",puerto_32765&16,tsconf_af_ports[0x21] &1);
banco=((puerto_32765>>4)&1) | 2;
}
}
//printf ("page0 %d banco %d\n",page0,banco);
return page0 | banco;
}
}
z80_byte tsconf_get_ram_bank_c0(void)
{
//De momento mapear como un 128k
z80_byte tsconf_lck=tsconf_get_memconfig_lck();
/*
00 512 kb 7ffd[7:6]=page3[4:3]
01 128 kb 7ffd[7:6]=00
10 auto !a[13] ???????
11 1024kb #7FFD[7:6] = Page3[4:3], #7FFD[5] = Page3[5]
Port 0x7FFD is an alias of Page3, thus selects page in 0xC000-0xFFFF window. Its behaviour depends on MemConfig LCK128 bits.
00 - 512k: #7FFD[7:6] -> Page3[4:3], #7FFD[2:0] -> Page3[2:0], Page3[7:5] = 0,
01 - 128k: #7FFD[2:0] -> Page3[2:0], Page3[7:3] = 0,
10 - Auto: OUT (#FD) works as mode 01, OUT (C), r works as mode 00,
11 - 1024k: #7FFD[7:6] -> Page3[4:3], #7FFD[2:0] -> Page3[2:0], #7FFD[5] -> Page3[5], Page3[7:6] = 0.
Port 0x7FFD is an alias of Page3, page3=tsconf_af_ports[0x13];
*/
z80_byte banco=0;
switch (tsconf_lck) {
case 0:
banco=(puerto_32765&7)| ((puerto_32765>>3)&24);
break;
case 1:
banco=puerto_32765&7;
break;
default:
cpu_panic("TODO invalid value for tsconf_lck");
break;
}
return banco;
}
z80_byte tsconf_get_text_font_page(void)
{
//En teoria es la misma pagina que registro af vpage(01) xor 1 pero algo falla, nos guiamos por pagina mapeada en segmento c0
//z80_byte pagina=tsconf_get_ram_bank_c0() ^ 1;
z80_byte pagina=tsconf_af_ports[1] ^ 1;
return pagina;
}
z80_byte tsconf_get_vram_page(void)
{
return tsconf_af_ports[1];
}
void tsconf_set_memory_pages(void)
{
z80_byte rom_page=tsconf_get_rom_bank();
z80_byte ram_page_40=tsconf_af_ports[17];
z80_byte ram_page_80=tsconf_af_ports[18];
z80_byte ram_page_c0=tsconf_af_ports[19];
/*
TODO
Port 1FFDh (read/write)
Bit 0 If 1 maps banks 8 or 9 at 0000h (switch off rom).
Bit 1 High bit of ROM selection and bank 8 (0) or 9 (1) if bit0 = 1.
*/
//memconfig
//bit3 selects what is in #0000..#3FFF (0 - ROM, 1 - RAM).
if (tsconf_get_memconfig()&8) {
debug_paginas_memoria_mapeadas[0]=rom_page;
tsconf_memory_paged[0]=tsconf_ram_mem_table[rom_page];
}
else {
debug_paginas_memoria_mapeadas[0]=DEBUG_PAGINA_MAP_ES_ROM+rom_page;
tsconf_memory_paged[0]=tsconf_rom_mem_table[rom_page];
}
tsconf_memory_paged[1]=tsconf_ram_mem_table[ram_page_40];
tsconf_memory_paged[2]=tsconf_ram_mem_table[ram_page_80];
tsconf_memory_paged[3]=tsconf_ram_mem_table[ram_page_c0];
debug_paginas_memoria_mapeadas[1]=ram_page_40;
debug_paginas_memoria_mapeadas[2]=ram_page_80;
debug_paginas_memoria_mapeadas[3]=ram_page_c0;
//printf ("32765: %02XH rom %d ram1 %d ram2 %d ram3 %d\n",puerto_32765,rom_page,ram_page_40,ram_page_80,ram_page_c0);
}
void tsconf_hard_reset(void)
{
debug_printf(VERBOSE_DEBUG,"TSconf Hard reset cpu");
reset_cpu();
int i;
//por que borramos fmaps??? for (i=0;i<TSCONF_FMAPS_SIZE;i++) tsconf_fmaps[i]=0;
//Borro sprites. dejo paleta sin tocar pues hay alguna demo que usa la paleta por defecto (pixeldemo)
for (i=0x200;i<0x400;i++) tsconf_fmaps[i]=0;
//Borrar toda memoria ram
int d;
z80_byte *puntero;
for (i=0;i<TSCONF_RAM_PAGES;i++) {
puntero=tsconf_ram_mem_table[i];
for (d=0;d<16384;d++,puntero++) {
*puntero=0;
}
}
//Valores por defecto
tsconf_af_ports[0]=0;
tsconf_af_ports[1]=5;
tsconf_af_ports[2]=0;
tsconf_af_ports[3] &=(255-1);
tsconf_af_ports[4]=0;
tsconf_af_ports[5] &=(255-1);
tsconf_af_ports[6] &=3;
tsconf_af_ports[7]=15;
//Paginas RAM
tsconf_af_ports[0x10]=0;
tsconf_af_ports[0x11]=5;
tsconf_af_ports[0x12]=2;
tsconf_af_ports[0x13]=0;
tsconf_af_ports[0x15] &=(255-16);
tsconf_af_ports[0x20]=1;
temp_tsconf_in_system_rom_flag=1;
tsconf_af_ports[0x21]=4;
tsconf_af_ports[0x22]=1;
tsconf_af_ports[0x23]=0;
tsconf_af_ports[0x24] &=(2+4+8);
tsconf_af_ports[0x29] &=(255-1-2-4-8);
tsconf_af_ports[0x2A] &=(255-1-2-4);
tsconf_af_ports[0x2A] |=1;
tsconf_af_ports[0x2B] &=(255-1-2-4-8);
//Los registros de scroll, del 40h al 47h, en la documentacion dice que no se toca,
//pero yo lo cambio porque sino , hay demos que se ven mal pues conservan valores anteriores
tsconf_af_ports[0x40]=0;
tsconf_af_ports[0x41]=0;
tsconf_af_ports[0x42]=0;
tsconf_af_ports[0x43]=0;
tsconf_af_ports[0x44]=0;
tsconf_af_ports[0x45]=0;
tsconf_af_ports[0x46]=0;
tsconf_af_ports[0x47]=0;
//idem, dice no tocar pero lo cambio a 0
tsconf_af_ports[0x1A]=0;
tsconf_af_ports[0x1B]=0;
tsconf_af_ports[0x1C]=0;
tsconf_af_ports[0x1D]=0;
tsconf_af_ports[0x1E]=0;
tsconf_af_ports[0x1F]=0;
tsconf_set_memory_pages();
tsconf_set_sizes_display();
tsconf_set_emulator_setting_turbo();
}
//Funcion para convertir paleta de 5 bits de tsconf a 8 bits (rgb15 a rgb24)
//Tiene en cuenta parametro vdac de tsconf , si esta disponible o no
z80_byte tsconf_rgb_5_to_8(z80_byte color)
{
//Si tsconf usa paletas inferiores de 2,3 o 4 bits, quitar bits
//tsconf_palette_depth (default 5)
if (tsconf_palette_depth==2) color=color&(255-1-2-4); //quitamos los 3 bits inferiores
if (tsconf_palette_depth==3) color=color&(255-1-2); //quitamos los 2 bits inferiores
if (tsconf_palette_depth==4) color=color&(255-1); //quitamos el 1 bit inferior
//Con pwm
if (tsconf_vdac_with_pwm.v==0) return color*8; //5 bits: 0..31. max valor 31*8=248
//con pwm cada componente de 5 bits son diferentes hasta valor 24, a partir de ahi son iguales a 255:
/*
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
0, 10, 21, 31, 42, 53, 63, 74, 85, 95, 106, 117, 127, 138, 149, 159, 170, 181, 191, 202, 213, 223, 234, 245, 255,
Y a partir de 24 todos son 255
*/
if (color>=24) return 255;
//entre 0 y 23
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
z80_byte without_vdac[24]={0, 10, 21, 31, 42, 53, 63, 74, 85, 95, 106, 117, 127, 138, 149, 159, 170, 181, 191, 202, 213, 223, 234, 245};
return without_vdac[color];
}
//Hace putpixel tsconf pero teniendo en cuenta desplazamiento de border, que en el caso de tsconf es variable
void scr_tsconf_putpixel_sum_border(int x,int y,unsigned color)
{
//tsconf_current_border_width almacena el ancho de una franja, la izquierda por ejemplo
//Dado que el border (y la zona de pixeles) son pixeles de tamanyo 2x2, multiplicar en ancho y alto
scr_putpixel_zoom(x+tsconf_current_border_width*2,y+tsconf_current_border_height*2,color);
}
//Hace putpixel pero teniendo en cuenta tamanyo de 1x2
void scr_tsconf_putpixel_text_mode(int x,int y,unsigned color)
{
y*=2;
int border_x=tsconf_current_border_width*2;
int border_y=tsconf_current_border_height*2;
int menu_x=(x+border_x)/8;
int menu_y=(y+border_y)/8;
//Suponemos que y e y+1 van a estar dentro de una cuadricula igual los dos, por tanto la comprobacion siguiente solo la hacemos una vez
if (scr_ver_si_refrescar_por_menu_activo(menu_x,menu_y)) {
scr_tsconf_putpixel_sum_border(x,y,color);
scr_tsconf_putpixel_sum_border(x,y+1,color);
}
}
//Hace putpixel pero teniendo en cuenta tamanyo de 2x2
void scr_tsconf_putpixel_zx_mode(int x,int y,unsigned color)
{
y*=2;
x*=2;
int border_x=tsconf_current_border_width*2;
int border_y=tsconf_current_border_height*2;
int menu_x=(x+border_x)/8;
int menu_y=(y+border_y)/8;
//Suponemos que x, x+1 e y e y+1 van a estar dentro de una cuadricula igual los dos, por tanto la comprobacion siguiente solo la hacemos una vez
if (scr_ver_si_refrescar_por_menu_activo(menu_x,menu_y)){
scr_tsconf_putpixel_sum_border(x,y,color);
scr_tsconf_putpixel_sum_border(x,y+1,color);
scr_tsconf_putpixel_sum_border(x+1,y,color);
scr_tsconf_putpixel_sum_border(x+1,y+1,color);
}
}
void scr_tsconf_putpixel_zoom_rainbow_text_mode(unsigned color,z80_int *puntero_rainbow,int ancho_linea)
{
//puntero_rainbow +=margeny_arr*ancho_linea;
//puntero_rainbow +=margenx_izq;
*puntero_rainbow=color;
puntero_rainbow +=ancho_linea;
*puntero_rainbow=color;
}
//Muestra un caracter en pantalla, al estilo del spectrum o zx80/81 o jupiter ace
//entrada: puntero=direccion a tabla del caracter
//ink, paper
void scr_tsconf_putsprite_comun(z80_byte *puntero,int alto,int x,int y,z80_bit inverse,z80_byte tinta,z80_byte papel,z80_int *puntero_layer)
{
z80_int color;
z80_byte bit;
z80_byte line;
z80_byte byte_leido;
for (line=0;line<alto;line++,y++) {
byte_leido=*puntero++;
if (inverse.v==1) byte_leido = byte_leido ^255;
for (bit=0;bit<8;bit++) {
if (byte_leido & 128 ) color=tinta;
else color=papel;
byte_leido=(byte_leido&127)<<1;
if (puntero_layer!=NULL) {
//Lo mete en buffer rainbow
color=tsconf_return_cram_color(tsconf_return_cram_palette_offset()+color);
//scr_tsconf_putpixel_zoom_rainbow_text_mode(color,puntero_rainbow,ancho_rainbow);
*puntero_layer=color;
puntero_layer++;
}
else {
color=tsconf_return_cram_color(tsconf_return_cram_palette_offset()+color);
//if (scr_ver_si_refrescar_por_menu_activo((x+bit)/8,y/8)) {
scr_tsconf_putpixel_text_mode(x+bit,y,TSCONF_INDEX_FIRST_COLOR+color);
//}
}
}
//puntero_rainbow=puntero_rainbow_orig;
//puntero_rainbow +=ancho_rainbow;
}
}
int tsconf_get_current_visible_scanline(void)
{
return t_scanline_draw-screen_invisible_borde_superior;
}
int temp_conta_nogfx;
z80_byte tsconf_get_border_colour(void)
{
return tsconf_af_ports[0xF];
}
//tipo: 0 arriba, abajo. 1 izquierda derecha
void tsconf_store_scanline_border_supinf_izqder(int tipo)
{
//printf ("border\n");
// tsconf_current_border_width=(360-tsconf_current_pixel_width)/2;
//tsconf_current_border_height=(288-tsconf_current_pixel_height)/2;
//Si no esta esa capa, salir
if (tsconf_force_disable_layer_border.v) return;
//Si borde invisible superior
int visible_scanline=tsconf_get_current_visible_scanline();
if (visible_scanline<0) return;
int ancho_linea;
ancho_linea=get_total_ancho_rainbow();
//alto=get_total_alto_rainbow();
z80_int *destino;
destino=&rainbow_buffer[visible_scanline*2*ancho_linea]; //doble pixel en altura
int color; //TODO. solo pillamos un color por scanline
color=tsconf_get_border_colour();
//color=TSCONF_INDEX_FIRST_COLOR+tsconf_return_cram_color (tsconf_return_cram_palette_offset()+color);
color=TSCONF_INDEX_FIRST_COLOR+tsconf_return_cram_color(color);
// printf ("Refresco border\n");
int x;
//parte superior e inferior
if (tipo==0) {
for (x=0;x<ancho_linea;x++) {
*destino=color;
destino[ancho_linea]=color; //doble pixel en altura
destino++;
}
}
//laterales
if (tipo==1) {
int ancho_border=tsconf_current_border_width*2;
for (x=0;x<ancho_border;x++) {
//izq
*destino=color;
destino[ancho_linea]=color; //doble pixel en altura
//der
destino[ancho_border+tsconf_current_pixel_width*2]=color;
destino[ancho_border+tsconf_current_pixel_width*2+ancho_linea]=color; //doble pixel en altura
destino++;
}
}
//laterales
/*for (y=0;y<tsconf_current_pixel_height;y++) {
for (x=0;x<tsconf_current_border_width;x++) {
scr_tsconf_putpixel_zoom_border(x,y+tsconf_current_border_height,color);
scr_tsconf_putpixel_zoom_border(x+tsconf_current_border_width+tsconf_current_pixel_width,y+tsconf_current_border_height,color);
}
}*/
}
void tsconf_store_scanline_ula(void)
{
int scanline_copia=tsconf_get_current_visible_scanline();
//linea que se debe leer
scanline_copia -=tsconf_current_border_height;
int y_origen_pixeles=scanline_copia;
//sumar offset
int y_offset=tsconf_af_ports[4]+256*(tsconf_af_ports[5]&1);
y_origen_pixeles +=y_offset;
//controlar si sale de rango
y_origen_pixeles=y_origen_pixeles % 512;
int x,bit;
z80_int direccion;
z80_int dir_atributo;
z80_byte byte_leido;
int color=0;
int fila;
z80_byte attribute,bright,flash;
z80_int ink,paper,aux;
z80_byte *screen=get_base_mem_pantalla();
direccion=screen_addr_table[(y_origen_pixeles<<5)];
fila=y_origen_pixeles/8;
dir_atributo=6144+(fila*32);
int puntero_layer_ula=0;
z80_byte videomode=tsconf_get_video_mode_display();
if (videomode==3) {
//modo texto
int ancho_caracter=8;
int ancho_linea=tsconf_current_pixel_width*2;
z80_int puntero=0x0000;
z80_byte *screen;
screen=tsconf_ram_mem_table[tsconf_get_vram_page() ];
//int ancho_linea_caracteres=256;
int x=0;
int y=y_origen_pixeles;
puntero=fila*256;
z80_byte font_page=tsconf_get_text_font_page();
z80_byte *puntero_fuente;
puntero_fuente=tsconf_ram_mem_table[font_page];
//z80_int puntero_orig=puntero;
z80_byte caracter;
//z80_byte caracter_text;
z80_bit inverse;
inverse.v=0;
z80_int offset_caracter;
//z80_byte tinta,papel;
unsigned int tinta,papel;
z80_byte atributo;
for (x=0;x<ancho_linea;x+=ancho_caracter) {
caracter=screen[puntero];
atributo=screen[puntero+128];
puntero++;
offset_caracter=caracter*8;
//Sumarle scanline % 8
offset_caracter +=(y % 8);
//No tengo ni idea de si se leen los atributos asi, pero parece similar al real
tinta=atributo&15;
papel=(atributo>>4)&15;
scr_tsconf_putsprite_comun(&puntero_fuente[offset_caracter],1,x,y,inverse,tinta,papel,&tsconf_layer_ula[puntero_layer_ula]);
puntero_layer_ula+=ancho_caracter;
}
}
//16 o 256 clores
if (videomode==1 || videomode==2) {
//puntero a vram
//Indice a linea
int offset;
int x_offset=tsconf_af_ports[2]+256*(tsconf_af_ports[3]&1);
//if (x_offset) printf ("x_offset: %d\n",x_offset);
//edge grinder y 200.spg y lirus y ppal y tcircles y twist0 y unhinged y wavering usan scroll x
int posicion_byte_inicial;
//Posicion y inicial
//16 colores
if (videomode==1) {
offset=y_origen_pixeles*256;
//offset +=x_offset/2;
//posicion_byte_inicial=x_offset/2;
}
//256 colores
else {
offset=y_origen_pixeles*512;
//offset +=x_offset;
//posicion_byte_inicial=x_offset;
}
//Ver cuantas paginas salta esto
int pagina_offset=offset/16384;
//y offset final
z80_int offset_final=offset % 16384;
z80_byte vram_page=tsconf_get_vram_page()+pagina_offset;
z80_byte *screen;
screen=tsconf_ram_mem_table[vram_page]+offset_final;
z80_byte *screen_izquierda=screen; //primera posicion con x=0
//Sumamos scrolll x
//16 colores
if (videomode==1) {
screen +=x_offset/2;
posicion_byte_inicial=x_offset/2;
}
//256 colores
else {
screen +=x_offset;
posicion_byte_inicial=x_offset;
}
z80_byte color,color_orig;
z80_int color_final;
for (x=0;x<tsconf_current_pixel_width;x++,posicion_byte_inicial++) {
if (videomode==2) { //256 colores
color=*screen;
}
if (videomode==1) { //16 colores
color_orig=*screen;
//pixel de la izquierda
color=(color_orig>>4)&0xF;
//Con paleta
color +=tsconf_return_cram_palette_offset();
color_final=tsconf_return_cram_color(color);
//doble ancho
tsconf_layer_ula[puntero_layer_ula++]=color_final;
tsconf_layer_ula[puntero_layer_ula++]=color_final;
x++;
//pixel de la derecha
color=color_orig&0xF;
//Con paleta
color +=tsconf_return_cram_palette_offset();
}
color_final=tsconf_return_cram_color(color);
//doble ancho
tsconf_layer_ula[puntero_layer_ula++]=color_final;
tsconf_layer_ula[puntero_layer_ula++]=color_final;
screen++;
if (posicion_byte_inicial>=512) { //Volver a inicial
//printf ("---LLegado scroll derecha\n");
screen=screen_izquierda;
posicion_byte_inicial=0;
}
}
}
if (videomode==0) {
//temp
//z80_byte vram_page=tsconf_get_vram_page();
//z80_byte *screen;
//screen=tsconf_ram_mem_table[vram_page];
for (x=0;x<32;x++) {
byte_leido=screen[direccion];
attribute=screen[dir_atributo];
//attribute=56;
//printf ("byte %d atributo %d\n",byte_leido,attribute);
ink=attribute &7;
paper=(attribute>>3) &7;
bright=(attribute)&64;
flash=(attribute)&128;
if (flash) {
if (estado_parpadeo.v) {
aux=paper;
paper=ink;
ink=aux;
}
}
if (bright) {
paper+=8;
ink+=8;
}
for (bit=0;bit<8;bit++) {
color= ( byte_leido & 128 ? ink : paper ) ;
color= tsconf_return_cram_color (tsconf_return_cram_palette_offset()+color);
//color=tsconf_return_cram_color(color);
//doble ancho
//color=44;
//doble ancho
tsconf_layer_ula[puntero_layer_ula++]=color;
tsconf_layer_ula[puntero_layer_ula++]=color;
//printf ("color final: %d\n",color);
byte_leido=byte_leido<<1;
}
direccion++;
dir_atributo++;
}
}
}
//Hace putpixel doble de ancho
//No lo uso, lo hago directamente desde las funciones que lo usan para que gaste menos cpu
/*
void tsconf_store_scanline_putsprite_putpixel(z80_int *puntero,z80_int color,z80_byte spal)
{
//Con paleta
z80_int color_final=tsconf_return_cram_color(color+16*spal);
*puntero=color_final;
puntero++;
*puntero=color_final;
}
*/
int tsconf_current_tile_written_index=0;
z80_int *tsconf_current_tile_written_pointer;
void tsconf_put_tile_pixel(z80_int color,z80_byte spal)
{
if (color) {
//color=tsconf_return_cram_color(color+16*spal);
color=tsconf_return_cram_color(color|spal);
*tsconf_current_tile_written_pointer=color;
tsconf_current_tile_written_pointer++;
*tsconf_current_tile_written_pointer=color;
tsconf_current_tile_written_pointer++;
}
else {
tsconf_current_tile_written_pointer+=2;
}
tsconf_current_tile_written_index+=2;
if (tsconf_current_tile_written_index==1024) {
tsconf_current_tile_written_index=0;
tsconf_current_tile_written_pointer-=1024;
}
}
//Solo tiles
void tsconf_store_scanline_puttiles(int ancho, int incx,z80_byte spal,z80_byte *sprite_origen)
{
z80_byte byte_sprite;
z80_int color_izq,color_der;
for (;ancho;ancho-=2) { //-=2 porque son a 4bpp
byte_sprite=*sprite_origen;
if (incx==-1) {
color_der=(byte_sprite>>4)&15;
color_izq=byte_sprite&15;
}
else {
color_izq=(byte_sprite>>4)&15;
color_der=byte_sprite&15;
}
tsconf_put_tile_pixel(color_izq,spal);
tsconf_put_tile_pixel(color_der,spal);
sprite_origen+=incx;
}
}
//Solo sprites
void tsconf_store_scanline_putsprite(int x_orig,int incx,int ancho, int tnum_x GCC_UNUSED, int tnum_y GCC_UNUSED,z80_byte spal,z80_byte *sprite_origen,z80_int *layer)
{
z80_int *puntero_buf_sprite;
//puntero_buf_sprite=&tsconf_layer_sprites[ x*2 ];
//puntero_buf_sprite=&layer[ x*2 ];
//destino
puntero_buf_sprite=&layer[x_orig*2];
z80_byte byte_sprite;
z80_int color_final;
for (;ancho;ancho-=2) { //-=2 porque son a 4bpp
byte_sprite=*sprite_origen;
z80_int color_izq;
z80_int color_der;
//si mirror
if (incx==-1) {
color_der=(byte_sprite>>4)&15;
color_izq=byte_sprite&15;
}
else {
color_izq=(byte_sprite>>4)&15;
color_der=byte_sprite&15;
}
if (color_izq) { //0 es transparente
//Lo hacemos asi para que sea mas rapido
color_final=tsconf_return_cram_color(color_izq+16*spal);
*puntero_buf_sprite=color_final;
puntero_buf_sprite++;
*puntero_buf_sprite=color_final;
puntero_buf_sprite++;
}
else {
puntero_buf_sprite+=2;
}
x_orig++;
if (x_orig>=512) {
x_orig=0;
puntero_buf_sprite=layer;
}
if (color_der) { //0 es transparente
//Lo hacemos asi para que sea mas rapido
color_final=tsconf_return_cram_color(color_der+16*spal);
*puntero_buf_sprite=color_final;
puntero_buf_sprite++;
*puntero_buf_sprite=color_final;
puntero_buf_sprite++;
}
else {
puntero_buf_sprite+=2;
}
x_orig++;
if (x_orig>=512) {
x_orig=0;
puntero_buf_sprite=layer;
}
sprite_origen+=incx;
}
}
int tsconf_return_spritesgraphicspage(void)
{
int direccion=tsconf_af_ports[0x19]>>3;
direccion=direccion & 31;
direccion=direccion << 17;
return direccion;
}
void tsconf_store_scanline_sprites_putsprite(int x,int incx,int y_offset,int ancho, int tnum_x, int tnum_y,z80_byte spal,z80_int *layer)
{
/*int direccion=tsconf_af_ports[0x19]>>3;
direccion=direccion & 31;
direccion=direccion << 17;*/
int direccion=tsconf_return_spritesgraphicspage();
z80_byte *sprite_origen;
sprite_origen=tsconf_ram_mem_table[0];
sprite_origen +=direccion;
int ancho_linea=256; //512 pixeles a 4bpp
tnum_x *=8;
tnum_y *=8;
//a 4bpp
tnum_x /=2;
if (incx==-1) tnum_x=tnum_x+ancho/2-1;
sprite_origen+=(tnum_y*ancho_linea)+tnum_x;
//Sumar a sprite_origen el y_offset
sprite_origen +=y_offset*(ancho_linea);
//printf ("sprite_origen: %d\n",sprite_origen);
tsconf_store_scanline_putsprite(x,incx,ancho, tnum_x, tnum_y,spal,sprite_origen,layer);
}
void tsconf_store_scanline_sprites(int capa_mostrar)
{
//linea que se debe leer
//int scanline_copia=t_scanline_draw-tsconf_current_border_height;
int scanline_copia=tsconf_get_current_visible_scanline();
scanline_copia -=tsconf_current_border_height;
if (scanline_copia<0) return;
int i;
int offset=0;
int salir=0;
int capa_actual=0;
z80_int *layer;
if (capa_mostrar==0) layer=tsconf_layer_sprites_zero;
if (capa_mostrar==1) layer=tsconf_layer_sprites_one;
if (capa_mostrar==2) layer=tsconf_layer_sprites_two;
//Los 85 sprites
for (i=0;i<TSCONF_MAX_SPRITES && !salir;i++,offset+=6) {
z80_byte sprite_r0h=tsconf_fmaps[0x200+offset+1];
z80_byte sprite_leap=sprite_r0h&64;
if (sprite_r0h&64) {
//salir=1; //Bit Leap, ultimo sprite
//printf ("\nUltimo sprite");
}
//Si sprite activo y es de esta capa
if (sprite_r0h&32 && capa_actual==capa_mostrar) {
int y=tsconf_fmaps[0x200+offset]+256*(sprite_r0h&1);
z80_byte ysize=8*(1+((sprite_r0h>>1)&7));
//Ver si esta en rango y
if (scanline_copia>=y && scanline_copia<y+ysize) {
z80_byte sprite_r1h=tsconf_fmaps[0x200+offset+3];
int x=tsconf_fmaps[0x200+offset+2]+256*(sprite_r1h&1);
z80_byte xsize=8*(1+((sprite_r1h>>1)&7));
z80_byte sprite_r2h=tsconf_fmaps[0x200+offset+5];
z80_int tnum=(tsconf_fmaps[0x200+offset+4])+256*(sprite_r2h&15);
//Tile Number for upper left corner. Bits 0-5 are X Position in Graphics Bitmap, bits 6-11 - Y Position.
z80_int tnum_x=tnum & 63;
z80_int tnum_y=(tnum>>6)&63;
z80_byte spal=(sprite_r2h>>4)&15;
/*
En demo ny17, xsize=ysize=32. tnum_x va de 0,4,8, etc. Asumimos que para posicionar en el sprite adecuado,
es un desplazamiento de tnum_x*8. Mismo para tnum_y
Para pasar de cada coordenada y, hay que sumar 512 pixeles (son de 4bpp), por tanto, 256 direcciones
*/
//if (x>320) printf ("\nsprite %d x: %d y: %d xs: %d ys: %d tnum_x: %d tnum_y: %d spal: %d",i,x,y,xsize,ysize,tnum_x,tnum_y,spal);
//temp_sprite_xy(x,y,1+8);
int y_offset=scanline_copia-y;
//printf ("\nscanline: %d yoff: %d sprite %d x: %d y: %d xs: %d ys: %d tnum_x: %d tnum_y: %d spal: %d",scanline_copia,y_offset,i,x,y,xsize,ysize,tnum_x,tnum_y,spal);
//temp_sprite_xy_putsprite(x,y,xsize,ysize,tnum_x,tnum_y,spal);
//Si hay mirror vertical
if (sprite_r0h&128) {
y_offset=ysize-1-y_offset;
}
//int final_layer_x_offset=x*2; //*2 porque la resolucion de pixeles es de 360 maximo mientras que el scanline entero es de 720,
//y solo se pueden usar 720 con el modo texto
int incx=+1;
//Si hay mirror horizontal
if (sprite_r1h&128) {
//tnum_x=tnum_x-xsize/2;
incx=-1;
}
tsconf_store_scanline_sprites_putsprite(x,incx,y_offset,xsize,tnum_x,tnum_y,spal,layer);
}
}
if (sprite_leap) capa_actual++;
if (capa_actual>2) salir=1;
}
//printf ("\n");
}
//Retorna los dos bytes de definicion de un tile para una columna x dada (teniendo en cuenta que >=64, resetea a 0)
void tsconf_tile_return_column_values(z80_byte *start_line,int x,z80_byte *valor1,z80_byte *valor2)
{
x=x&63;
z80_byte *puntero=&start_line[x*2];
*valor1=*puntero;
puntero++;
*valor2=*puntero;
}
int tsconf_return_tilegraphicspage(z80_byte layer)
{
int direccion_graficos=tsconf_af_ports[0x17+layer]>>3;
direccion_graficos=direccion_graficos & 31;
direccion_graficos=direccion_graficos<<17;
return direccion_graficos;
}
int tsconf_return_tilemappage(void)
{
int direccion_tile=tsconf_af_ports[0x16];
direccion_tile=direccion_tile<< 14;
return direccion_tile;
}
void tsconf_store_scanline_tiles(z80_byte layer,z80_int *layer_tiles)
{
int scanline_copia=tsconf_get_current_visible_scanline();
//linea que se debe leer
scanline_copia -= tsconf_current_border_height;
//TODO: tener en cuenta zona invisible border ??
if (scanline_copia<0) return;
int direccion_graficos=tsconf_return_tilegraphicspage(layer);
int direccion_tile=tsconf_return_tilemappage();
//printf ("direccion_tile: %06XH\n",direccion_tile);
z80_byte *puntero_layer;
z80_byte *puntero_graficos;
puntero_layer=tsconf_ram_mem_table[0]+direccion_tile;
puntero_graficos=tsconf_ram_mem_table[0]+direccion_graficos;
z80_byte puntero_offset_scroll=0x40+4*layer;
int offset_x=tsconf_af_ports[puntero_offset_scroll]+256*(tsconf_af_ports[puntero_offset_scroll+1]&1);
int offset_y=tsconf_af_ports[puntero_offset_scroll+2]+256*(tsconf_af_ports[puntero_offset_scroll+3]&1);
//aplicar offset_y
scanline_copia +=offset_y;
//if (offset_y<0) return;
//http://forum.tslabs.info/viewtopic.php?f=35&t=157
int y=scanline_copia/8;
//Valores mayores que 64, volver al principio
y=y&63;
puntero_layer +=256*y; //Cada linea en mapa de tiles ocupa 256 bytes
//Lo de antes es equivalente a:
//puntero_layer +=32*(scanline_copia & 0xFFF8); //Ignorar los primeros 3 bits, es como dividir entre 8 y multiplicar de nuevo por 8
/*
O sea: se almacena en la forma (64 (layer0) + 64 (layer1)) x 64 tile = (128 + 128) x 64 bytes = 16kB = 1 page
En la misma zona de memoria estan los 64 datos de layer0 (2 bytes por cada) y los 64 datos de layer1
*/
//printf ("scanline: %d tile y: %d\n",scanline_copia,y);
puntero_layer +=128*layer;
//En que scanline esta 0...7
int desplazamiento_scanline=(scanline_copia & 7)*256;
//Cada linea del bitmap ocupa 256 bytes
z80_byte valor1, valor2;
int total_tiles;
int tile_x;
tile_x=offset_x/8;
tile_x=0;
tsconf_current_tile_written_index=-offset_x*2;
if (tsconf_current_tile_written_index<0) {
tsconf_current_tile_written_index +=1024;
}
tsconf_current_tile_written_pointer=&layer_tiles[tsconf_current_tile_written_index];
///printf ("index: %d\n",tsconf_current_tile_written_index);
z80_byte *sprite_origen;
for (total_tiles=0;total_tiles<64;total_tiles++,tile_x++) {
tsconf_tile_return_column_values(puntero_layer,tile_x,&valor1,&valor2);
z80_int tnum=valor1+256*(valor2&15);
//z80_byte tpal=(valor2>>4)&3;
z80_byte tpal=(valor2)&(32+16);
//Tile Palette Selector, bits 0-1. Bits 2-3 are taken from PalSel register bits 6-7 or 4-5, dependently on tiles layer 1 or 0.
z80_byte palsel=tsconf_af_ports[7];
z80_byte tpal_23;
/*if (layer==0) {
tpal_23=(palsel>>2)&(4+8); //bits 4-5 los muevo a 2-3
}
else {
tpal_23=(palsel>>4)&(4+8); //bits 6-7 los muevo a 2-3
}*/
if (layer==0) {
tpal_23=(palsel<<2)&(64+128); //bits 4-5 los muevo a 6-7
}
else {
tpal_23=(palsel)&(64+128); //bits 6-7 los dejo en 6-7
}
tpal |=tpal_23;
int tnum_x=tnum&63;
int tnum_y=(tnum>>6)&63;
//z80_byte tile_xf=puntero_layer[1] & 64;
//z80_byte tile_yf=puntero_layer[1] & 128;
z80_byte tile_xf=valor2 & 64;
z80_byte tile_yf=valor2 & 128;
sprite_origen=puntero_graficos+(tnum_y*256*8);
int incx;
if (tile_xf) {
incx=-1;
sprite_origen +=tnum_x*8/2+3;
//printf ("x mirror\n");
}
else {
incx=+1;
sprite_origen +=tnum_x*8/2;
}
//printf ("desplazamiento scanline: %d\n",desplazamiento_scanline);
if (tile_yf) {
//printf ("y mirror. layer: %d tnum_x: %d tnum_y: %d\n",layer,tnum_x,tnum_y);
//sprite_origen +=7*256-desplazamiento_scanline;
sprite_origen=sprite_origen+(7*256)-desplazamiento_scanline;
}
else {
sprite_origen +=desplazamiento_scanline;
}
tsconf_store_scanline_puttiles(8, incx, tpal,sprite_origen);
}
}
int tsconf_if_ula_enabled(void)
{
if (tsconf_af_ports[0]&32) return 0;
return 1;
}
int tsconf_if_sprites_enabled(void)
{
z80_byte tsconfig=tsconf_af_ports[6];
if (tsconfig&128) return 1;
else return 0;
//printf ("Sprite layers enable ");
}
int tsconf_if_tiles_zero_enabled(void)
{
z80_byte tsconfig=tsconf_af_ports[6];
if (tsconfig&32) return 1;
else return 0;
}
int tsconf_if_tiles_one_enabled(void)
{
z80_byte tsconfig=tsconf_af_ports[6];
if (tsconfig&64) return 1;
else return 0;
}
//Para zona de border o pantalla
void screen_store_scanline_rainbow_solo_display_tsconf(void)
{
int linea_render_visible=tsconf_get_current_visible_scanline();
//El dibujado de borde no es real. Tendria que usar un buffer border como en spectrum ,pero de momento ya me vale
/*
De momento he visto que la demo "fast" cambia los colores del border, aunque no todo el border de golpe, no a cada scanline
*/
//Zona de borde superior o inferior. Dibujar directamente en buffer rainbow
if (linea_render_visible<tsconf_current_border_height || linea_render_visible>=tsconf_current_border_height+tsconf_current_pixel_height) {
tsconf_store_scanline_border_supinf_izqder(0);
//No hay mas que eso en el scanline. volver
return;
}
//Border laterales. Dibujar directamente en buffer rainbow
tsconf_store_scanline_border_supinf_izqder(1);
//Inicializamos array de capas
int i;
for (i=0;i<TSCONF_MAX_WIDTH_LAYER;i++) {
tsconf_layer_ula[i]=tsconf_layer_tiles_zero[i]=tsconf_layer_tiles_one[i]=tsconf_layer_sprites_zero[i]=tsconf_layer_sprites_one[i]=tsconf_layer_sprites_two[i]=TSCONF_SCANLINE_TRANSPARENT_COLOR;
}
//Dibujamos las capas
//Capa ULA
if (tsconf_if_ula_enabled() && tsconf_force_disable_layer_ula.v==0) tsconf_store_scanline_ula();
//Si estamos en zona de superior o inferior, ni sprites ni tiles
int spritestiles=1;
//Y las pasamos a buffer rainbow
//printf ("scan line de pantalla fisica (no border): %d\n",t_scanline_draw);
//linea que se debe leer
int scanline_copia=linea_render_visible-tsconf_current_border_height;
//borde superior
if (scanline_copia<0) spritestiles=0;
//Si zona border inferior
if (scanline_copia>tsconf_current_pixel_height) spritestiles=0;
if (spritestiles) {
//if (tsconf_si_render_spritetile_rapido.v==0) {
if (1) {
//z80_byte tsconfig=tsconf_af_ports[6];
//if (tsconfig&128) {
if (tsconf_if_sprites_enabled() ) {
//printf ("Sprite layers enable ");
if (tsconf_force_disable_layer_sprites_zero.v==0) tsconf_store_scanline_sprites(0);
if (tsconf_force_disable_layer_sprites_one.v==0) tsconf_store_scanline_sprites(1);
if (tsconf_force_disable_layer_sprites_two.v==0) tsconf_store_scanline_sprites(2);
}
//if (tsconfig&32) {
if (tsconf_if_tiles_zero_enabled() ) {
//printf ("Tile layer 0 enable- ");
if (tsconf_force_disable_layer_tiles_zero.v==0) tsconf_store_scanline_tiles(0,tsconf_layer_tiles_zero);
}
//if (tsconfig&64) {
if (tsconf_if_tiles_one_enabled() ) {
//printf ("Tile layer 1 enable- ");
if (tsconf_force_disable_layer_tiles_one.v==0) tsconf_store_scanline_tiles(1,tsconf_layer_tiles_one);
}
}
}
int total_ancho_rainbow=get_total_ancho_rainbow();
//la copiamos a buffer rainbow
z80_int *puntero_buf_rainbow;
int y_rainbow=scanline_copia*2;
//printf ("store y: %d\n",y_rainbow);
puntero_buf_rainbow=&rainbow_buffer[ y_rainbow*total_ancho_rainbow ];
//Margenes border
puntero_buf_rainbow +=tsconf_current_border_width*2;
puntero_buf_rainbow +=total_ancho_rainbow*tsconf_current_border_height*2;
int x;
//scanline_copia tiene coordenada scanline de dentro de zona pantalla
z80_int *layer_one;
z80_int *layer_two;
z80_int *layer_three;
z80_int *layer_four;
z80_int *layer_five;
z80_int *layer_six;
//Sprites encima de tiles y encima de ula
layer_one=tsconf_layer_sprites_two;
layer_two=&tsconf_layer_tiles_one[0]; //Empieza en offset 8. Tenemos 8 pixeles de margen a la izquierda que no se ven
layer_three=tsconf_layer_sprites_one;
layer_four=&tsconf_layer_tiles_zero[0]; //Empieza en offset 8. Tenemos 8 pixeles de margen a la izquierda que no se ven
layer_five=tsconf_layer_sprites_zero;
layer_six=tsconf_layer_ula;
for (x=0;x<tsconf_current_pixel_width*2;x++) {
z80_int color_final;
//Gestion de capas
color_final=*layer_one;
if (color_final==TSCONF_SCANLINE_TRANSPARENT_COLOR) {
color_final=*layer_two;
if (color_final==TSCONF_SCANLINE_TRANSPARENT_COLOR) {
color_final=*layer_three;
if (color_final==TSCONF_SCANLINE_TRANSPARENT_COLOR) {
color_final=*layer_four;
if (color_final==TSCONF_SCANLINE_TRANSPARENT_COLOR) {
color_final=*layer_five;
if (color_final==TSCONF_SCANLINE_TRANSPARENT_COLOR) {
color_final=*layer_six;
//Si transparente, color 0
if (color_final==TSCONF_SCANLINE_TRANSPARENT_COLOR) color_final=0;
}
}
}
}
}
color_final +=TSCONF_INDEX_FIRST_COLOR;
*puntero_buf_rainbow=color_final;
//doble alto
*(puntero_buf_rainbow+total_ancho_rainbow)=color_final;
//Siguiente pixel
puntero_buf_rainbow++;
layer_one++;
layer_two++;
layer_three++;
layer_four++;
layer_five++;
layer_six++;
}
}
void screen_tsconf_refresca_text_mode(void)
{
int ancho_caracter=8;
int ancho_linea=tsconf_current_pixel_width*2;
int alto_pantalla=tsconf_current_pixel_height;
//z80_int puntero=0xc000;
z80_int puntero=0x0000;
z80_byte *screen;
screen=tsconf_ram_mem_table[tsconf_get_vram_page() ];
int ancho_linea_caracteres=256;
int x=0;
int y=0;
z80_byte font_page=tsconf_get_text_font_page();
z80_byte *puntero_fuente;
puntero_fuente=tsconf_ram_mem_table[font_page];
z80_int puntero_orig=puntero;
z80_byte caracter;
//z80_byte caracter_text;
z80_bit inverse;
inverse.v=0;
z80_int offset_caracter;
z80_byte tinta,papel;
z80_byte atributo;
for (;puntero<7680;) {
caracter=screen[puntero];
atributo=screen[puntero+128];
//printf ("%d ",atributo);
puntero++;
offset_caracter=caracter*8;
//No tengo ni idea de si se leen los atributos asi, pero parece similar al real
tinta=atributo&15;
papel=(atributo>>4)&15;
scr_tsconf_putsprite_comun(&puntero_fuente[offset_caracter],8,x,y,inverse,tinta,papel,NULL);
x+=ancho_caracter;
if (x+ancho_caracter>ancho_linea) {
//printf ("\n");
x=0;
y+=8;
if (y+8>alto_pantalla) {
//provocar fin
puntero=7680;
}
puntero=puntero_orig+ancho_linea_caracteres; //saltar atributos
puntero_orig=puntero;
}
}
}
//Putpixel de pixeles 2x2 de border de tsconf para modo no rainbow
void scr_tsconf_putpixel_zoom_border(int x,int y, unsigned int color)
{
x*=2;
y*=2;
int menu_x=x/8;
int menu_y=y/8;
//Suponemos que x, x+1 e y e y+1 van a estar dentro de una cuadricula igual los dos, por tanto la comprobacion siguiente solo la hacemos una vez
if (scr_ver_si_refrescar_por_menu_activo(menu_x,menu_y)){
scr_putpixel_zoom(x,y,color);
scr_putpixel_zoom(x+1,y,color);
scr_putpixel_zoom(x,y+1,color);
scr_putpixel_zoom(x+1,y+1,color);
}
}
void scr_refresca_border_tsconf_cont(void)
{
int color;
color=tsconf_get_border_colour();
color=TSCONF_INDEX_FIRST_COLOR+tsconf_return_cram_color(color);
if (scr_refresca_sin_colores.v) color=7;
// printf ("Refresco border\n");
int x,y;
//Top border cambia en spectrum y zx8081 y ace
//int topborder=TOP_BORDER;
//parte superior e inferior
for (y=0;y<tsconf_current_border_height;y++) {
for (x=0;x<TSCONF_DISPLAY_WIDTH/2;x++) {
scr_tsconf_putpixel_zoom_border(x,y,color);
scr_tsconf_putpixel_zoom_border(x,y+tsconf_current_pixel_height+tsconf_current_border_height,color);
}
}
//laterales
for (y=0;y<tsconf_current_pixel_height;y++) {
for (x=0;x<tsconf_current_border_width;x++) {
scr_tsconf_putpixel_zoom_border(x,y+tsconf_current_border_height,color);
scr_tsconf_putpixel_zoom_border(x+tsconf_current_border_width+tsconf_current_pixel_width,y+tsconf_current_border_height,color);
}
}
}
void screen_tsconf_refresca_border(void)
{
//if (rainbow_enabled.v==0) {
if (border_enabled.v) {
//ver si hay que refrescar border
if (modificado_border.v) {
scr_refresca_border_tsconf_cont();
modificado_border.v=0;
}
}
//}
}
//z80_int temp_cc=0;
//Refresco pantalla sin rainbow en tsconf
void scr_tsconf_refresca_pantalla_zxmode_no_rainbow_comun(void)
{
//printf ("refresca\n");
int x,y,bit;
z80_int direccion,dir_atributo;
z80_byte byte_leido;
int color=0;
int fila;
//int zx,zy;
z80_byte attribute,ink,paper,bright,flash,aux;
z80_byte *screen;
z80_byte vram_page=tsconf_get_vram_page();
//vram_page=temp_cc/64;
//temp_cc++;
//printf ("refresca modo 0. vram: %d\n",vram_page);
screen=tsconf_ram_mem_table[vram_page];
//temp
//screen=tsconf_ram_mem_table[tsconf_af_ports[1]];
//printf ("dpy=%x ventana=%x gc=%x image=%x\n",dpy,ventana,gc,image);
z80_byte x_hi;
for (y=0;y<192;y++) {
direccion=screen_addr_table[(y<<5)];
fila=y/8;
dir_atributo=6144+(fila*32);
for (x=0,x_hi=0;x<32;x++,x_hi +=8) {
//Ver en casos en que puede que haya menu activo y hay que hacer overlay
if (1==1) {
//if (scr_ver_si_refrescar_por_menu_activo(x,fila)) {
byte_leido=screen[direccion];
attribute=screen[dir_atributo];
if (scr_refresca_sin_colores.v) attribute=56;
ink=attribute &7;
paper=(attribute>>3) &7;
bright=(attribute) &64;
flash=(attribute)&128;
if (flash) {
//intercambiar si conviene
if (estado_parpadeo.v) {
aux=paper;
paper=ink;
ink=aux;
}
}
if (bright) {
ink +=8;
paper +=8;
}
for (bit=0;bit<8;bit++) {
color= ( byte_leido & 128 ? ink : paper );
color=TSCONF_INDEX_FIRST_COLOR+ tsconf_return_cram_color (tsconf_return_cram_palette_offset()+color);
scr_tsconf_putpixel_zx_mode(x_hi+bit,y,color);
byte_leido=byte_leido<<1;
}
}
//temp
//else {
// printf ("no refrescamos zona x %d fila %d\n",x,fila);
//}
direccion++;
dir_atributo++;
}
}
}
z80_byte temp_conta_ts=0;
z80_byte temp_conta_ts2=0;
//Refresco pantalla sin rainbow en tsconf
void scr_tsconf_refresca_pantalla_16c_256c_no_rainbow(int modo)
{
int x,y;
z80_byte color;
z80_int puntero=0;
z80_byte vrampage;
vrampage=tsconf_get_vram_page();
z80_byte *screen=tsconf_ram_mem_table[vrampage];
for (y=0;y<tsconf_current_pixel_height;y++) {
z80_int puntero_orig=puntero;
for (x=0;x<tsconf_current_pixel_width;) {
//Ver en casos en que puede que haya menu activo y hay que hacer overlay
if (1==1) {
//if (scr_ver_si_refrescar_por_menu_activo(x,fila)) {
if (modo==1) { //16c
color=screen[puntero++];
//printf ("color: %d\n",color);
scr_tsconf_putpixel_zx_mode(x++,y,TSCONF_INDEX_FIRST_COLOR+ tsconf_return_cram_color (tsconf_return_cram_palette_offset()+( (color>>4)&0xF) ) );
scr_tsconf_putpixel_zx_mode(x++,y,TSCONF_INDEX_FIRST_COLOR+ tsconf_return_cram_color (tsconf_return_cram_palette_offset()+ (color&0xF) ) );
}
if (modo==2) { //256c
color=screen[puntero++];
scr_tsconf_putpixel_zx_mode(x++,y,TSCONF_INDEX_FIRST_COLOR+tsconf_return_cram_color(color) );
}
}
}
//Siguiente linea
if (modo==1) puntero=puntero_orig+256;
else puntero=puntero_orig+512;
if (puntero>=16384) {
puntero=0;
vrampage++;
screen=tsconf_ram_mem_table[vrampage];
}
}
}
void scr_tsconf_refresca_pantalla_zxmode_no_rainbow(void)
{
/*if (border_enabled.v) {
//ver si hay que refrescar border
if (modificado_border.v) {
//screen_prism_refresca_no_rainbow_border(color);
scr_refresca_border_tsconf_cont();
modificado_border.v=0;
}
}*/
scr_tsconf_refresca_pantalla_zxmode_no_rainbow_comun();
}
void screen_tsconf_refresca_rainbow(void) {
int ancho,alto;
ancho=get_total_ancho_rainbow();
alto=get_total_alto_rainbow();
//printf ("ancho: %d alto: %d\n",ancho,alto);
int x,y,bit;
//margenes de zona interior de pantalla. Para overlay menu
/*int margenx_izq=screen_total_borde_izquierdo*border_enabled.v;
int margenx_der=screen_total_borde_izquierdo*border_enabled.v+512;
int margeny_arr=screen_borde_superior*border_enabled.v;
int margeny_aba=screen_borde_superior*border_enabled.v+384;*/
//en tsconf menu no aparece con margen de border. Sale tal cual desde 0,0
//para overlay menu tambien
z80_int color_pixel;
z80_int *puntero;
puntero=rainbow_buffer;
int dibujar;
int menu_x,menu_y;
for (y=0;y<alto;y++) {
for (x=0;x<ancho;x+=8) {
dibujar=1;
//Ver si esa zona esta ocupada por texto de menu u overlay.
// Como tsconf usa menu doble de tamanyo, multiplicamos por valor de menu_gui_zoom que sera 2 siempre (seria lo mismo
//que poner y<384 && x<512, pero queda mas explicativo en este caso y se puede usar el mismo if para diferentes maquinas
if (y<192*menu_gui_zoom && x<256*menu_gui_zoom) {
dibujar=0;
menu_x=x/8;
menu_y=y/8;
if (scr_ver_si_refrescar_por_menu_activo(menu_x,menu_y)) dibujar=1;
}
if (dibujar==1) {
//printf ("dibujamos en X: %d y: %d\n",x,y);
for (bit=0;bit<8;bit++) {
color_pixel=*puntero++;
scr_putpixel_zoom_rainbow(x+bit,y,color_pixel);
}
}
else puntero+=8;
}
}
}
void screen_tsconf_refresca_pantalla(void)
{
//Como spectrum clasico
//modo clasico. sin rainbow
if (rainbow_enabled.v==0) {
screen_tsconf_refresca_border();
z80_byte modo_video=tsconf_get_video_mode_display();
//printf ("modo video: %d\n",modo_video );
if (modo_video==0) scr_tsconf_refresca_pantalla_zxmode_no_rainbow();
if (modo_video==1) scr_tsconf_refresca_pantalla_16c_256c_no_rainbow(1);
if (modo_video==2) scr_tsconf_refresca_pantalla_16c_256c_no_rainbow(2);
if (modo_video==3) screen_tsconf_refresca_text_mode();
}
else {
//modo rainbow - real video
screen_tsconf_refresca_rainbow();
}
}
void tsconf_get_debug_sprite(int sprite,struct s_tsconf_debug_sprite *dest)
{
//Para debug, retornar info de sprite X (0..84)
sprite=sprite%TSCONF_MAX_SPRITES;
int offset=sprite*6;
z80_byte sprite_r0h=tsconf_fmaps[0x200+offset+1];
dest->leap=sprite_r0h&64;
dest->act=sprite_r0h&32;
dest->y=tsconf_fmaps[0x200+offset]+256*(sprite_r0h&1);
dest->ys=8*(1+((sprite_r0h>>1)&7));
z80_byte sprite_r1h=tsconf_fmaps[0x200+offset+3];
dest->x=tsconf_fmaps[0x200+offset+2]+256*(sprite_r1h&1);
dest->xs=8*(1+((sprite_r1h>>1)&7));
z80_byte sprite_r2h=tsconf_fmaps[0x200+offset+5];
z80_int tnum=(tsconf_fmaps[0x200+offset+4])+256*(sprite_r2h&15);
//Tile Number for upper left corner. Bits 0-5 are X Position in Graphics Bitmap, bits 6-11 - Y Position.
dest->tnum_x=tnum & 63;
dest->tnum_y=(tnum>>6)&63;
dest->spal=(sprite_r2h>>4)&15;
dest->xf=sprite_r1h&128;
dest->yf=sprite_r0h&128;
}
z80_byte tsconf_vector_fired_interrupt=0xFF;
void tsconf_generate_im1_im2(z80_byte vector)
{
tsconf_vector_fired_interrupt=vector;
interrupcion_maskable_generada.v=1;
}
void tsconf_fire_line_interrupt(void)
{
tsconf_generate_im1_im2(253);
}
void tsconf_fire_frame_interrupt(void)
{
tsconf_generate_im1_im2(255);
}
int tsconf_handle_frame_interrupts_prev_horiz=9999;
//Para no disparar interrupcion dos interrupcion frame en misma linea . temporal
//int tsconf_last_frame_y=-1;
void tsconf_handle_frame_interrupts(void)
{
//Depende de DI???
if (iff1.v==0) return;
//registro intmask 2aH bit 1
if ((tsconf_af_ports[0x2a]&1)==0) return;
//printf ("tsconf raster line mask");
z80_byte int_raster_x=(tsconf_af_ports[0x22]);
//Si > 223, desactivado
if (int_raster_x>223) return;
int int_raster_y=(tsconf_af_ports[0x23])+256*(tsconf_af_ports[0x24]&1);
//Si >319, desactivado
if (int_raster_y>319) return;
//temp. Si <2, desactivado
//if (int_raster_y<2) return;
//printf ("tsconf raster set to %d %d\n",int_raster_x,int_raster_y);
//Ver en que posicion de t-estados por linea estamos
int estados_en_linea=t_estados % screen_testados_linea;
//Dividir por turbo
//estados_en_linea /=cpu_turbo_speed;
//primero comparar scanline
if (t_scanline==int_raster_y) {
//printf ("t: %d estados_en_linea: %d raster_x: %d last_interrupt: %d",t_estados,estados_en_linea,int_raster_x,tsconf_handle_frame_interrupts_prev_horiz);
//printf ("disparada raster y: %d \n",int_raster_y);
//Y ahora ver si nos "hemos" pasado de la posicion estados_en_linea anterior
if (estados_en_linea>=int_raster_x && estados_en_linea<tsconf_handle_frame_interrupts_prev_horiz) {
//temp saltar sin tener en cuenta posicion X
//if (t_scanline>tsconf_last_frame_y) {
//Generar interrupcion
tsconf_fire_frame_interrupt();
//debug_printf (VERBOSE_DEBUG,"Fired frame interrupt. VSINT: %d , HSINT: %d . scanline: %d , states in line: %d. vint_inc: %X",
// int_raster_y,int_raster_x,t_scanline,estados_en_linea,(tsconf_af_ports[0x24]>>4)&0xF);
//printf ("Reg VSINTH: %d\n",tsconf_af_ports[0x24]);
//printf ("tsconf raster set to line %d x %d\n",int_raster_y,int_raster_x);
//printf ("Fired frame interrupt. VSINT: %d , HSINT: %d . scanline: %d , states in line: %d. vint_inc: %X\n",
//int_raster_y,int_raster_x,t_scanline,estados_en_linea,(tsconf_af_ports[0x24]>>4)&0xF);
tsconf_handle_frame_interrupts_prev_horiz=estados_en_linea;
//tsconf_last_frame_y=t_scanline;
}
}
}
void tsconf_handle_line_interrupts(void)
{
//Depende de DI???
if (iff1.v==0) return;
//registro intmask 2aH bit 1
if ((tsconf_af_ports[0x2a]&2)==0) return;
//printf ("line interrupt set and fired at line %d\n",t_scanline);
tsconf_fire_line_interrupt();
}
const z80_byte tsconf_default_basic_palette[]={
0x00,0x00,0x10,0x00,0x00,0x40,0x10,0x40,0x00,0x02,0x10,0x02,0x00,0x42,0x10,0x42,0x08,0x21,0x18,0x00,0x00,0x60,0x18,0x60,0x00,0x03,0x18,0x03,0x00,0x63,0x18,0x63
};
//Inicializar tabla de colores 240-255 pues hay juegos, como pixeldemo, que usan dichos colores, y si se carga desde linea de comandos, sin pasar por la bios de tsconf, la paleta esta vacia
void tsconf_set_default_basic_palette(void)
{
debug_printf(VERBOSE_DEBUG,"Initializing TSConf basic palette (240-255)");
int index=240*2;
int i;
for (i=0;i<16*2;i++) {
tsconf_fmaps[index+i]=tsconf_default_basic_palette[i];
}
}
void tsconf_set_emulador_settings(void)
{
//Sincronizar settings de emulador con los valores de puertos de tsconf
tsconf_set_emulator_setting_turbo();
}