#include "spg.h" #include "Renderer_if.h" #include "regs.h" #include "threadedPvr.h" #include //SPG emulation; Scanline/Raster beam registers & interrupts //Time to emulate that stuff correctly ;) u32 in_vblank=0; u32 clc_pvr_scanline; u32 pvr_numscanlines=512; u32 prv_cur_scanline=-1; u32 vblk_cnt=0; u32 last_fps=0; volatile bool render_end_pending=false; u32 render_end_pending_cycles; //54 mhz pixel clock :) #define PIXEL_CLOCK (54*1000*1000/2) u32 Line_Cycles=0; u32 Frame_Cycles=0; void CalculateSync() { //clc_pvr_scanline=0; u32 pixel_clock; float scale_x=1,scale_y=1; if (FB_R_CTRL.vclk_div) { //VGA :) pixel_clock=PIXEL_CLOCK; } else { //It is half for NTSC/PAL pixel_clock=PIXEL_CLOCK/2; } //We need to caclulate the pixel clock // u32 sync_cycles=(SPG_LOAD.hcount+1)*(SPG_LOAD.vcount+1); pvr_numscanlines=SPG_LOAD.vcount+1; Line_Cycles=(u32)((u64)DCclock*(u64)(SPG_LOAD.hcount+1)/(u64)pixel_clock); if (SPG_CONTROL.interlace) { //this is a temp hack Line_Cycles/=2; // u32 interl_mode=VO_CONTROL.field_mode; //if (interl_mode==2)//3 will be funny =P // scale_y=0.5f;//single interlace //else scale_y=1; } else { if (FB_R_CTRL.vclk_div) { scale_y=1.0f;//non interlaced vga mode has full resolution :) } else scale_y=0.5f;//non interlaced modes have half resolution } SetFBScale(scale_x,scale_y); //Frame_Cycles=(u64)DCclock*(u64)sync_cycles/(u64)pixel_clock; Frame_Cycles=pvr_numscanlines*Line_Cycles; } extern u32 op_usage[0x10000]; extern u8* DynarecCache; extern u32 DynarecCacheSize; extern u64 time_dr_start; extern u64 time_update_system; extern u64 time_rw_regs; extern u64 time_gdrom; extern u64 time_lookup; extern u64 time_pref; extern u64 time_ta; extern u32 gdromaccesses; void PrintBlocksRunCount(); void spgVBL() { u32 curtime=timeGetTime(); //Vblank counter vblk_cnt++; params.RaiseInterrupt(holly_HBLank);// -> This turned out to be HBlank btw , needs to be emulated ;( //TODO : rend_if_VBlank(); VBlank();//notify for vblank :) UpdateRRect(); if ((curtime-last_fps)>500) { double spd_fps=(double)(FrameCount)/(double)((double)(curtime-(double)last_fps)/1000); double spd_vbs=(double)(vblk_cnt)/(double)((double)(curtime-(double)last_fps)/1000); double spd_cpu=spd_vbs*Frame_Cycles; spd_cpu/=1000000; //mrhz kthx double fullvbs=(spd_vbs/spd_cpu)*200; // wchar fpsStr[256]; const char* mode=0; const char* res=0; res=SPG_CONTROL.interlace?"480i":"240p"; if (SPG_CONTROL.NTSC==0 && SPG_CONTROL.PAL==1) mode="PAL"; else if (SPG_CONTROL.NTSC==1 && SPG_CONTROL.PAL==0) mode="NTSC"; else { res=SPG_CONTROL.interlace?"480i":"480p"; mode="VGA"; } if(kbhit()) { u32 i,j; u32 cumulcnt[0x200]={0}; switch(getch()) { case 'x': threaded_term(); exit(0); break; case 'o': printf("---- IFB op usage\n"); for(i=0;i<0x10000;++i) { if (op_usage[i]) { sh4_opcodelistentry* opentry=OpDesc[i]; for(j=0;j Line_Cycles)//60 ~herz = 200 mhz / 60=3333333.333 cycles per screen refresh { //ok .. here , after much effort , we did one line //now , we must check for raster beam interrupts and vblank prv_cur_scanline=(prv_cur_scanline+1)%pvr_numscanlines; clc_pvr_scanline -= Line_Cycles; //Check for scanline interrupts -- really need to test the scanline values if (SPG_VBLANK_INT.vblank_in_interrupt_line_number == prv_cur_scanline) params.RaiseInterrupt(holly_SCANINT1); if (SPG_VBLANK_INT.vblank_out_interrupt_line_number == prv_cur_scanline) params.RaiseInterrupt(holly_SCANINT2); if (SPG_VBLANK.vstart == prv_cur_scanline) in_vblank=1; if (SPG_VBLANK.vbend == prv_cur_scanline) in_vblank=0; if (SPG_CONTROL.interlace) SPG_STATUS.fieldnum=~SPG_STATUS.fieldnum; else SPG_STATUS.fieldnum=0; SPG_STATUS.vsync=in_vblank; SPG_STATUS.scanline=prv_cur_scanline; //Vblank start -- really need to test the scanline values if (prv_cur_scanline==0) { spgVBL(); } } if (render_end_pending) { if (render_end_pending_cycles