Re: [hatari-devel] Falcon raster emulation

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


Hi,

I've given a closer look at my old Videl code.

To understand what follows, I strongly suggest to read the Videl part of Mikro's site (in the documentation area)

Here is what I did 2 years ago :

- I replaced all the video.c code by videl code for VBL, HBL, ... (see below)
- I added some Videl interrupts.

The videl doesn't work like the ST Shifter.

In the videl registers, you can read the number of "VIDEL cycles" for a HBL.
You can get also the number of HBL for a VBL.

The VIDEL can work at 25 or 32 Mhz.

The display is composed of 2 HBL per line (except in some special cases).

So, I generated a half_HBL interrupt. Every other half_HBL interrupt, I send a HBL interrupt
When I reach the correct number of HBL, I send a VBL interrupt.

I've put here my old code (Videl part only). 
I think it could be used as a start to write something better.
If someone wants the complete code, I can zip it. 
It's based on hatari V1.5 or V1.6 I guess, but the falcon Videl part didn't move a lot.


I'm pretty sure this is the good way to proceed, but I may have done some things wrong here (or maybe I encountered timings problems, I don't remenber).
Maybe I should include this into the current hatari version with a compiler define to able/disable it.
The define could be removed when it works well.


Don't hesitate to ask if you have questions.

Reading this code again, I think some datas should be float, not int32 (cycles mainly).


Regards
Laurent

[added at the end of the videl.c code, after the rendering code]




/**
 * Start internal halfFrame Interrupt (25 or 32 Mhz)
 */
static void VIDEL_Start_Interrupt_HalfLine(void)
{
	Uint32 videlFreq = IoMem_ReadWord(0xff82c0) & 0x4;
	Uint32 hht_cycles = IoMem_ReadWord(0xff8282) + 2;
	Uint32 cycles;
	
	if (videlFreq) {
		/* 25 Mzh Frequency */
		cycles = ((hht_cycles * 25) / 32) / 2;
	}
	else {
		/* 32 Mzh Frequency */
		cycles = hht_cycles / 2;
	}

	VIDEL_updateInternalValues();
	videl.saveCycle = cycles;
//	fprintf(stderr ,"VIDEL HHT_cycles : %d\n", cycles);
	CycInt_AddRelativeInterrupt(cycles, INT_CPU_CYCLE, INTERRUPT_VIDEL_HALFLINE);
}

/**
 * Start internal HBL Interrupt (25 or 32 Mhz)
 */
static void VIDEL_Start_Interrupt_HBL(void)
{
	Uint32 hht_cycles = IoMem_ReadWord(0xff8282) + 2;
	Uint32 hhs_cycles = IoMem_ReadWord(0xff828c);

	Uint32 cycles = (hhs_cycles * videl.saveCycle) / hht_cycles;
//	fprintf(stderr ,"VIDEL HBL_cycles : %d\n", cycles);
	CycInt_AddRelativeInterrupt(cycles, INT_CPU_CYCLE, INTERRUPT_VIDEL_HBL);
}

void VIDEL_InterruptHandler_HBL(void)
{	
	/* Remove this interrupt from list and re-order */
	CycInt_AcknowledgeInterrupt();

	/* "normal" case, this HBL doesn't occur during the processing of a pending HBL */
	M68000_Exception(EXCEPTION_HBLANK , M68000_EXC_SRC_AUTOVEC);	/* Horizontal blank interrupt, level 2! */
}

void VIDEL_InterruptHandler_HalfLine(void)
{	
	Uint32 curr_HSS, curr_HHT, curr_VFC, curr_VFT, curr_VSS, curr_VBB, curr_VBE;
	int PendingCyclesOver;

	/* How many cycle was this HBL delayed (>= 0) */
	PendingCyclesOver = -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );

	/* Remove this interrupt from list and re-order */
	CycInt_AcknowledgeInterrupt();

	curr_HSS = IoMem_ReadWord(0xff828c);
	curr_HHT = IoMem_ReadWord(0xff8282);
	curr_VFC = IoMem_ReadWord(0xff820a) + 1;
	curr_VFT = IoMem_ReadWord(0xff82a2);
	curr_VSS = IoMem_ReadWord(0xff82ac);
	curr_VBB = IoMem_ReadWord(0xff82a4);
	curr_VBE = IoMem_ReadWord(0xff82a6);
	
	IoMem_WriteWord(0xff820a, curr_VFC);

	/* second half line starts, start a new Hsync timer */
	if ((curr_VFC & 1) == 1) {
		if (curr_HSS <= curr_HHT + 1)
			VIDEL_Start_Interrupt_HBL();
	}
	else {
		/* Timer B occurs at END of first visible screen line in Event Count mode */
		if ( (curr_VFC > curr_VBE) && (curr_VFC < curr_VBB) ) {
			/* Handle Timer B when using Event Count mode */
			if (MFP_TBCR == 0x08)						/* Is timer in Event Count mode ? */
				MFP_TimerB_EventCount_Interrupt();			/* we have a valid timer B interrupt */
		}
	}

	/* VSync reached ? */
	if (curr_VFC == curr_VSS + 1)
		VIDEL_Handler_VBL();

	/* End of screen frame reached ? */
	if (curr_VFC >= curr_VFT)
		IoMem_WriteWord(0xff820a, 0);

	/* Start the next half line timer interrupt */
	VIDEL_Start_Interrupt_HalfLine();
}

static void VIDEL_Handler_VBL(void)
{
	/* Clear any key presses which are due to be de-bounced (held for one ST frame) */
	Keymap_DebounceAllKeys();

	Videl_DrawScreen();

	/* Check printer status */
	Printer_CheckIdleStatus();

	/* Update counter for number of screen refreshes per second */
	videl.vbl_count ++;

	/* Set video registers for frame */
	Videl_ClearOnVBL();

	/* Since we don't execute HBL functions in VDI mode, we've got to
	 * initialize the first HBL palette here when VDI mode is enabled. */
//	if (bUseVDIRes)
//lolo		Videl_StoreFirstLinePalette();

	/* Act on shortcut keys */
	ShortCut_ActKey();

	/* Record video frame is necessary */
	if ( bRecordingAvi )
		Avi_RecordVideoStream ();

	/* Store off PSG registers for YM file, is enabled */
	YMFormat_UpdateRecording();

	/* Generate 1/50th second of sound sample data, to be played by sound thread */
	Sound_Update_VBL();

//	LOG_TRACE(TRACE_VIDEO_VBL , "VBL %d video_cyc=%d pending_cyc=%d jitter=%d\n" ,
//	               nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , PendingCyclesOver , VblJitterArray[ VblJitterIndex ] );

	/* Vertical blank interrupt, level 4! */
	M68000_Exception(EXCEPTION_VBLANK, M68000_EXC_SRC_AUTOVEC);	

	/* Host computer synchro */
	Main_WaitOnVbl();
}

/**
 * Called on each VBL, set registers ready for frame
 */
static void Videl_ClearOnVBL(void)
{
	/* New screen, so VFC = 0 */
	IoMem_WriteWord(0xff820a, 0);

	/* Get screen address pointer */
	videl.videoBaseAddr = VIDEL_getVideoramAddress();
}

/**
 * Draw screen 
 */
static void Videl_DrawScreen(void)
{
	bool bScreenChanged;

	/* Skip frame if need to */
	if (videl.vbl_count % (nFrameSkips+1))
		return;

	/* Use extended VDI resolution? */
	if (bUseVDIRes) {
		/* If so, just copy whole screen on VBL rather than per HBL */
		/* (don't care about being exact as for GEM only) */
//lolo		memcpy(pSTScreen, pVideoRaster, ((VDIWidth*VDIPlanes)/8)*VDIHeight);	
	}
	else {
		/* Draw the screen with Videl */
		bScreenChanged = VIDEL_renderScreen();
	}
}

static void VIDEL_updateInternalValues(void)
{	
	int i;
	Uint32 curr_VFC = IoMem_ReadWord(0xff820a) + 1;

	videl.internal_regs[curr_VFC].video_base = VIDEL_getVideoramAddress();
	videl.internal_regs[curr_VFC].video_count = 0; /* Todo */
	videl.internal_regs[curr_VFC].sync_mode = IoMem_ReadByte(0xff820a);
	videl.internal_regs[curr_VFC].offset_next_line = IoMem_ReadWord(0xff820e);
	videl.internal_regs[curr_VFC].line_width = IoMem_ReadWord(0xff8210);

	for (i=0; i<16; i++) 
		videl.internal_regs[curr_VFC].st_palette[i] =  IoMem_ReadWord(0xff8240 + (i*2));

	videl.internal_regs[curr_VFC].st_shift_mode = IoMem_ReadByte(0xff8260);
	videl.internal_regs[curr_VFC].h_scroll = IoMem_ReadWord(0xff8264);
	videl.internal_regs[curr_VFC].falcon_shift_mode = IoMem_ReadWord(0xff8266);

	videl.internal_regs[curr_VFC].HHC = IoMem_ReadWord(0xff8280);
	videl.internal_regs[curr_VFC].HHT = IoMem_ReadWord(0xff8282);
	videl.internal_regs[curr_VFC].HBB = IoMem_ReadWord(0xff8284);
	videl.internal_regs[curr_VFC].HBE = IoMem_ReadWord(0xff8286);
	videl.internal_regs[curr_VFC].HDB = IoMem_ReadWord(0xff8288);
	videl.internal_regs[curr_VFC].HDE = IoMem_ReadWord(0xff828a);
	videl.internal_regs[curr_VFC].HSS = IoMem_ReadWord(0xff828c);
	videl.internal_regs[curr_VFC].HFS = IoMem_ReadWord(0xff828e);
	videl.internal_regs[curr_VFC].HEE = IoMem_ReadWord(0xff8290);
	
	videl.internal_regs[curr_VFC].VFC = IoMem_ReadWord(0xff82a0);
	videl.internal_regs[curr_VFC].VFT = IoMem_ReadWord(0xff82a2);
	videl.internal_regs[curr_VFC].VBB = IoMem_ReadWord(0xff82a4);
	videl.internal_regs[curr_VFC].VBE = IoMem_ReadWord(0xff82a6);
	videl.internal_regs[curr_VFC].VDB = IoMem_ReadWord(0xff82a8);
	videl.internal_regs[curr_VFC].VDE = IoMem_ReadWord(0xff82aa);
	videl.internal_regs[curr_VFC].VSS = IoMem_ReadWord(0xff82ac);
	
	videl.internal_regs[curr_VFC].VCO = IoMem_ReadWord(0xff82c0);
	videl.internal_regs[curr_VFC].VMD = IoMem_ReadWord(0xff82c2);

	for (i=0; i<256; i++) 
		videl.internal_regs[curr_VFC].falcon_palette[i] =  IoMem_ReadWord(0xff9800 + (i*2));
}



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/