pcsx2/fps2bios/kernel/iopload/vblank/vblank.c

301 lines
7.2 KiB
C

#include "kloadcore.h"
#include "kintrman.h"
#include "ksysclib.h"
#include "kthbase.h"
#include "thevent.h"
#include "err.h"
#define _dprintf(fmt, args...) \
__printf("vblank: " fmt, ## args)
struct DCLL
{
struct DCLL *next;
struct DCLL *prev;
int priority;
int (*function)();
void *this; //'this' style pointer
}; //intrh_vblank, intrh_evblank, vblank_0, vblank_1
//cannot access global v
struct VBHS
{
int statusFlag; //set to 0 in 'start' function
int count;
struct DCLL list0; //sentinel, dummy list head (interrupt 0 vblank)
struct DCLL list11; //sentinel, dummy list head (interrupt 11 evblank)
struct DCLL free; //available blocks
struct DCLL items[16];
} v;
int _start();
struct VBHS *return_v();
int WaitVblankStart();
int WaitVblankEnd();
int WaitVblank();
int WaitNonVblank();
int RegisterVblankHandler(int number, int priority, int (*)(struct VBHS *), struct VBHS*);
int ReleaseVblankHandler(int number, int (*)(struct VBHS *));
void DCLL_del(struct DCLL *list);
void DCLL_add_before(struct DCLL *list, struct DCLL *new);
void DCLL_add_after(struct DCLL *list, struct DCLL *new);
///////////////////////////////////////////////////////////////////////
struct VBHS *return_v(){
return &v;
}
///////////////////////////////////////////////////////////////////////
int RegisterVblankHandler(int number, int priority, int (*handler)(struct VBHS *), struct VBHS* this)
{
struct DCLL *p, *list;
u32 x;
if (QueryIntrContext()){
_dprintf("%s - ERROR_INTR_CONTEXT\n", __FUNCTION__);
return ERROR_INTR_CONTEXT;
}
CpuSuspendIntr(&x);
if (DCLL_is_only_sentinel(&v.free)){
CpuResumeIntr(x);
_dprintf("%s - ERROR_NO_MEM\n", __FUNCTION__);
return ERROR_NO_MEM;
}
list=(number? &v.list11 : &v.list0); //which list: 0 or 11?
p=list->next;
if (p != list){ //search for an existing instance in the list
do{
if (p->function == handler){
CpuResumeIntr(x); //intrman
return ERROR_DOES_EXIST;//already added
}
p=p->next;
}while(p != list);
p = list->next;
}
while (p != list){ // while we have elements in list ...
if (priority < p->priority)
break; //greater priority
p=p->next;
}
struct DCLL* node = v.free.next;
DCLL_del(node);
node->function=handler;
node->this =this;
node->priority=priority;
DCLL_add_after(p, node);
CpuResumeIntr(x);
return ERROR_OK;
}
///////////////////////////////////////////////////////////////////////
int ReleaseVblankHandler(int number, int (*handler)(struct VBHS *)){
struct DCLL *p, *list;
u32 x;
if (QueryIntrContext())
return ERROR_INTR_CONTEXT;
CpuSuspendIntr(&x);
for (list=(number?&v.list11:&v.list0), p=list->next; p!=list; p=p->next)
if (p->function == handler){ //bingo
DCLL_del(p);
DCLL_add_before(&v.free, p);
CpuResumeIntr(x);
return ERROR_OK;
}
CpuResumeIntr(x);
return ERROR_DOESNOT_EXIST; //not found
}
///////////////////////////////////////////////////////////////////////
int intrh_vblank(struct VBHS *m)
{
struct DCLL *p;
struct DCLL *cp;
if (m->count++ == 0){
iSetEventFlag(GetSystemStatusFlag(), 0x200);
}
for (p = m->list0.next; p != &(m->list0); p = cp){
cp=p->next;
if ((p->function)(p->this)==0){
DCLL_del(p);
DCLL_add_before(&m->free, p);
}
}
return 1;
}
///////////////////////////////////////////////////////////////////////
int intrh_evblank(struct VBHS *m)
{
struct DCLL *p, *cp;
_dprintf("%s\n", __FUNCTION__);
for (p=m->list11.next; p != &m->list11; p=cp ){
cp=p->next;
if ((p->function)(p->this)==0){
DCLL_del(p);
DCLL_add_before(&m->free, p);
}
}
return 1;
}
///////////////////////////////////////////////////////////////////////
int vblankh_0(struct VBHS *m)
{
// _dprintf("%s\n", __FUNCTION__);
iSetEventFlag(m->statusFlag, 1); // 0001b //thevent
iSetEventFlag(m->statusFlag, 2); // 0010b //thevent
iClearEventFlag(m->statusFlag, ~(1|8));//~(1001b)=0xFFFFFFF6//thevent
return 1;
}
///////////////////////////////////////////////////////////////////////
int vblankh_1(struct VBHS *m)
{
_dprintf("%s\n", __FUNCTION__);
iSetEventFlag(m->statusFlag, 4); // 0100b //thevent
iSetEventFlag(m->statusFlag, 8); // 1000b //thevent
iClearEventFlag(m->statusFlag, ~(2|4));//~(0110b)=0xFFFFFFF9//thevent
return 1;
}
///////////////////////////////////////////////////////////////////////
int WaitVblankStart(){
return WaitEventFlag(v.statusFlag, 1, 1, 0); //thevent
}
///////////////////////////////////////////////////////////////////////
int WaitVblankEnd(){
return WaitEventFlag(v.statusFlag, 4, 1, 0); //thevent
}
///////////////////////////////////////////////////////////////////////
int WaitVblank(){
return WaitEventFlag(v.statusFlag, 2, 1, 0); //thevent
}
///////////////////////////////////////////////////////////////////////
int WaitNonVblank(){
return WaitEventFlag(v.statusFlag, 8, 1, 0); //thevent
}
///////////////////////////////////////////////////////////////////////
//static allocated Double Cyclic sentinel priority Linked List (whew)//
///////////////////////////////////////////////////////////////////////
void DCLL_make_sentinel(struct DCLL *list){
list->next=list;
list->prev=list;
}
///////////////////////////////////////////////////////////////////////
int DCLL_is_only_sentinel(struct DCLL *list){
return (list->next == list);
}
///////////////////////////////////////////////////////////////////////
// x <-> list <-> y
// becomes
// x <-> y
void DCLL_del(struct DCLL *list)
{
struct DCLL* x = list->prev;
struct DCLL* y = list->next;
x->next = y;
y->prev = x;
}
///////////////////////////////////////////////////////////////////////
void DCLL_add_before(struct DCLL *list, struct DCLL *new)
{
new->next=list;
new->prev=list->prev;
list->prev=new;
new->prev->next=new;
}
//
// list <-> x
// list <-> new <-> x
void DCLL_add_after(struct DCLL *list, struct DCLL *new)
{
struct DCLL *x = list->next;
new->prev = list;
new->next = x;
list->next = new;
x->prev = new;
}
void _retonly(){}
//////////////////////////////entrypoint///////////////////////////////
struct export export_stub={
0x41C00000,
0,
VER(1, 1), // 1.1 => 0x101
0,
"vblank\0\0",
(func)_start, // entrypoint
(func)_retonly,
(func)_retonly,
(func)return_v,
(func)WaitVblankStart, // 4
(func)WaitVblankEnd, // 5
(func)WaitVblank, // 6
(func)WaitNonVblank, // 7
(func)RegisterVblankHandler, // 8
(func)ReleaseVblankHandler, // 9
0 // end of list
};
//////////////////////////////entrypoint///////////////////////////////
int _start(){
iop_event_t e;
u32 x;
int i;
CpuSuspendIntr(&x);
if (RegisterLibraryEntries(&export_stub)){
CpuResumeIntr(x);
return 1;
}
memset(&v, 0, sizeof(struct VBHS)); // 352 //sysclib
DCLL_make_sentinel(&v.list0);
DCLL_make_sentinel(&v.list11);
DCLL_make_sentinel(&v.free);
for (i=0; i<16; i++){ //link 16 elements
DCLL_add_after(&v.free, &v.items[i]);//to 'available' list
}
e.bits=0;
e.attr=2;
e.option=0;
CreateEventFlag(&e); //thevent
v.statusFlag=0;
RegisterVblankHandler(0, 128, vblankh_0, &v);
RegisterVblankHandler(1, 128, vblankh_1, &v);
RegisterIntrHandler( 0, 1, (intrh_func)intrh_vblank, &v);
RegisterIntrHandler(11, 1, (intrh_func)intrh_evblank,&v);
EnableIntr(0);
EnableIntr(11);
CpuResumeIntr(x);
return 0;
}