mirror of
https://git.checksum.fail/alec/bahamut.git
synced 2026-05-26 13:38:35 +00:00
Add files to repository
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
uncrustify.cfg
|
||||
.vscode/
|
||||
ROMs/
|
||||
SnesJs/
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
extern I64 frames;
|
||||
|
||||
Context2D *font_ctx = LoadPNG("font.png",,,2);
|
||||
Context2D *font_ch = NewContext2D(16, 16, display.bpp);
|
||||
|
||||
U0 FontChar2D(Context2D *ctx, I64 ch, I64 x, I64 y)
|
||||
{
|
||||
ch-=32;
|
||||
Fill2D(font_ch, font_ch->alpha_color);
|
||||
Blot2D(font_ch, -(16*(ch%8)), -(16*(ch/8)), font_ctx);
|
||||
Blot2D(ctx, x, y, font_ch);
|
||||
}
|
||||
|
||||
U0 Font2D(Context2D *ctx, I64 x, I64 y, U8 *fmt,...)
|
||||
{
|
||||
U8 *buf;
|
||||
if (argc)
|
||||
{
|
||||
buf=StrPrintJoin(NULL, fmt, argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf=StrNew(fmt);
|
||||
}
|
||||
U8 *str=buf;
|
||||
while (*str)
|
||||
{
|
||||
FontChar2D(ctx, *str++, x, y);
|
||||
x += 16;
|
||||
}
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 PrintPlot2D(Context2D *ctx, I64 x, I64 y, U32 color)
|
||||
{
|
||||
U64 i = ctx->fb;
|
||||
I64 pos = (svga.width*y)*svga.bpp/8;
|
||||
pos += x*svga.bpp/8;
|
||||
(i+pos)(U8*)[0]=color.u8[1];
|
||||
(i+pos)(U8*)[1]=color.u8[2];
|
||||
(i+pos)(U8*)[2]=color.u8[3];
|
||||
}
|
||||
|
||||
U0 PrintChar2D(Context2D *ctx, I64 x, I64 y, I64 ch, U32 fg=0xFFFFFF00, U32 bg=BLACK)
|
||||
{
|
||||
U64 *char=sys_font_std;
|
||||
I64 xx,yy;
|
||||
I64 ii=0;
|
||||
for (yy=0; yy<8; yy++)
|
||||
{
|
||||
xx=0;
|
||||
for (xx=0; xx<8; xx++)
|
||||
{
|
||||
if (char[ch].u8[ii] & 1<<xx)
|
||||
{
|
||||
PrintPlot2D(ctx, x+xx, y+yy, fg);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintPlot2D(ctx, x+xx, y+yy, bg);
|
||||
}
|
||||
}
|
||||
ii++;
|
||||
if (ii>8)
|
||||
{
|
||||
ch++;
|
||||
ii=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 Print2D(Context2D *ctx, I64 x, I64 y, U32 fg=0xFFFFFFFF, U32 bg=0, U8 *fmt,...)
|
||||
{
|
||||
U8 *buf;
|
||||
if (argc)
|
||||
{
|
||||
buf=StrPrintJoin(NULL, fmt, argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf=StrNew(fmt);
|
||||
}
|
||||
U8 *str=buf;
|
||||
while (*str)
|
||||
{
|
||||
PrintChar2D(ctx, x, y, *str++, fg, bg);
|
||||
x += 8;
|
||||
}
|
||||
Free(buf);
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
tmpdoc = DocNew;
|
||||
origdoc = Fs->put_doc;
|
||||
Fs->put_doc = tmpdoc;
|
||||
|
||||
U0 EDbgPlot2D(I64 x, I64 y, U32 color)
|
||||
{
|
||||
U64 i = svga.fb;
|
||||
I64 pos = (svga.width*y)*svga.bpp/8;
|
||||
pos += x*svga.bpp/8;
|
||||
(i+pos)(U8*)[0]=color.u8[1];
|
||||
(i+pos)(U8*)[1]=color.u8[2];
|
||||
(i+pos)(U8*)[2]=color.u8[3];
|
||||
}
|
||||
|
||||
U0 EDbgChar2D(I64 x, I64 y, I64 ch, U32 fg=0xFFFFFF00, U32 bg=BLACK)
|
||||
{
|
||||
U64 *char=sys_font_std;
|
||||
I64 xx,yy;
|
||||
I64 ii=0;
|
||||
for (yy=0; yy<8; yy++)
|
||||
{
|
||||
xx=0;
|
||||
for (xx=0; xx<8; xx++)
|
||||
{
|
||||
if (char[ch].u8[ii] & 1<<xx)
|
||||
{
|
||||
EDbgPlot2D(x+xx, y+yy, fg);
|
||||
}
|
||||
else
|
||||
{
|
||||
EDbgPlot2D(x+xx, y+yy, bg);
|
||||
}
|
||||
}
|
||||
ii++;
|
||||
if (ii>8)
|
||||
{
|
||||
ch++;
|
||||
ii=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 EDbgPutChar(I64 ch)
|
||||
{
|
||||
if (!IsSingleUser) { return; };
|
||||
text.raw_flags &=~RWF_SHOW_DOLLAR;
|
||||
if (ch>'~' && ch!=219)
|
||||
{
|
||||
ch=' ';
|
||||
}
|
||||
I64 i,row,col;
|
||||
I64 raw_pos;
|
||||
I64 raw_y;
|
||||
U8 *ptr,*ptr1,*ptr2;
|
||||
|
||||
if (!(text.raw_flags&RWF_SHOW_DOLLAR)) {
|
||||
if (ch=='$$') {
|
||||
if (text.raw_flags&RWF_IN_DOLLAR) {
|
||||
text.raw_flags&=~RWF_IN_DOLLAR;
|
||||
if (!(text.raw_flags & RWF_LAST_DOLLAR)) {
|
||||
text.raw_flags&=~RWF_LAST_DOLLAR;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
text.raw_flags|=RWF_IN_DOLLAR|RWF_LAST_DOLLAR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
text.raw_flags&=~RWF_LAST_DOLLAR;
|
||||
if (text.raw_flags&RWF_IN_DOLLAR)
|
||||
return;
|
||||
}
|
||||
if (ch=='\t') {
|
||||
EDbgPutChar(CH_SPACE);
|
||||
while (text.raw_col & 7)
|
||||
EDbgPutChar(CH_SPACE);
|
||||
} else if (ch==CH_BACKSPACE) {
|
||||
text.raw_col--;
|
||||
EDbgPutChar(CH_SPACE);
|
||||
text.raw_col--;
|
||||
} else if (ch=='\n') {
|
||||
EDbgPutChar(CH_SPACE);
|
||||
while (text.raw_col % text.cols)
|
||||
EDbgPutChar(CH_SPACE);
|
||||
|
||||
} else if (Bt(char_bmp_displayable,ch)) {
|
||||
row=text.raw_col/text.cols%text.rows;
|
||||
col=text.raw_col%text.cols;
|
||||
if (text.raw_flags&RWF_SCROLL && text.raw_col && !row && !col) {
|
||||
for (raw_y=0; raw_y<(text.rows*8)-8; raw_y++)
|
||||
{
|
||||
MemCpy(svga.fb+(raw_y*svga.width*(svga.bpp/8)),
|
||||
svga.fb+((raw_y+8)*svga.width*(svga.bpp/8)),
|
||||
(text.cols*8)*(svga.bpp/8));
|
||||
}
|
||||
for (raw_y=(text.rows*8)-8; raw_y<(text.rows*8); raw_y++)
|
||||
{
|
||||
MemSet(svga.fb+(raw_y*svga.width*(svga.bpp/8)),
|
||||
0,
|
||||
(text.cols*8)*(svga.bpp/8));
|
||||
}
|
||||
text.raw_col-=text.cols;
|
||||
row=text.rows-1;
|
||||
}
|
||||
EDbgChar2D(col*8, row*8, ch);
|
||||
text.raw_col++;
|
||||
}
|
||||
}
|
||||
|
||||
Bool EKDRawPutKey(I64 ch,I64)
|
||||
{
|
||||
if (IsRaw) {
|
||||
EDbgPutChar(ch);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool EKDRawPutS(U8 *st)
|
||||
{
|
||||
I64 ch;
|
||||
if (IsRaw) {
|
||||
while (ch=*st++)
|
||||
EDbgPutChar(ch);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 RawDrNull(CTask *task=NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CKeyDevEntry *tmp_kde = keydev.put_key_head;
|
||||
while (tmp_kde->put_s != &KDRawPutS)
|
||||
{
|
||||
tmp_kde = tmp_kde->next;
|
||||
}
|
||||
tmp_kde->put_key = &EKDRawPutKey;
|
||||
tmp_kde->put_s = &EKDRawPutS;
|
||||
|
||||
MemCpy(&RawDr, &RawDrNull, sizeof(RawDrNull));
|
||||
|
||||
Bool Debug = FALSE;
|
||||
U0 resume() { Debug=FALSE; G2; };
|
||||
|
||||
Fs->put_doc = origdoc;
|
||||
DocDel(tmpdoc);
|
||||
@@ -0,0 +1,17 @@
|
||||
class Display
|
||||
{
|
||||
I64 width;
|
||||
I64 height;
|
||||
I64 bpp;
|
||||
};
|
||||
|
||||
Display display;
|
||||
|
||||
U0 DisplayInit()
|
||||
{
|
||||
display.width = 640;
|
||||
display.height = 480;
|
||||
display.bpp = 32;
|
||||
}
|
||||
|
||||
DisplayInit;
|
||||
@@ -0,0 +1,250 @@
|
||||
class Context2D
|
||||
{
|
||||
I64 width;
|
||||
I64 height;
|
||||
I64 bpp;
|
||||
I64 alpha_color;
|
||||
U8 *fb;
|
||||
};
|
||||
|
||||
Context2D *NewContext2D(I64 width, I64 height, I64 bpp=display.bpp)
|
||||
{ //Create new Context2D.
|
||||
switch (bpp)
|
||||
{
|
||||
case 32:
|
||||
case 24:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
Context2D *ctx = CAlloc(sizeof(Context2D));
|
||||
ctx->width = width;
|
||||
ctx->height = height;
|
||||
ctx->bpp = bpp;
|
||||
ctx->alpha_color = 0x00FF0000;
|
||||
ctx->fb = CAlloc((width*height)*bpp/8);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
U0 DelContext2D(Context2D *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Free(ctx->fb);
|
||||
Free(ctx);
|
||||
}
|
||||
|
||||
U0 Fill2D(Context2D *ctx, U32 color=U32_MAX)
|
||||
{ //Fill a Context2D with color.
|
||||
if (color==U32_MAX) color=ctx->alpha_color;
|
||||
U64 i = ctx->fb;
|
||||
I64 pos = 0;
|
||||
while (pos<(ctx->width*ctx->height)*ctx->bpp/8)
|
||||
{
|
||||
(i+pos)(U8*)[0]=color.u8[1];
|
||||
(i+pos)(U8*)[1]=color.u8[2];
|
||||
(i+pos)(U8*)[2]=color.u8[3];
|
||||
switch (ctx->bpp)
|
||||
{
|
||||
case 32:
|
||||
pos+=4;
|
||||
break;
|
||||
case 24:
|
||||
pos+=3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U32 Peek2D(Context2D *ctx, I64 x, I64 y)
|
||||
{ //Return RGB value for pixel.
|
||||
U32 color=0;
|
||||
if (x<0 || x>ctx->width-1 || y<0 || y>ctx->height-1)
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
U64 i = ctx->fb;
|
||||
I64 pos = (ctx->width*y)*(ctx->bpp/8);
|
||||
pos += x*(ctx->bpp/8);
|
||||
color.u8[1]=(i+pos)(U8*)[0];
|
||||
color.u8[2]=(i+pos)(U8*)[1];
|
||||
color.u8[3]=(i+pos)(U8*)[2];
|
||||
return color;
|
||||
}
|
||||
|
||||
U0 Plot2D(Context2D *ctx, I64 x, I64 y, U32 color)
|
||||
{ //Plot a pixel.
|
||||
if (x<0 || x>ctx->width-1 || y<0 || y>ctx->height-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
U64 i = ctx->fb;
|
||||
I64 pos = (ctx->width*y)*(ctx->bpp/8);
|
||||
pos += x*(ctx->bpp/8);
|
||||
(i+pos)(U8*)[0]=color.u8[1];
|
||||
(i+pos)(U8*)[1]=color.u8[2];
|
||||
(i+pos)(U8*)[2]=color.u8[3];
|
||||
}
|
||||
|
||||
U0 HLine2D(Context2D *ctx, I64 x, I64 y, I64 x2, U32 color)
|
||||
{ //Draw a horizontal line.
|
||||
if (x2<x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (x<x2+1)
|
||||
{
|
||||
Plot2D(ctx, x, y, color);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 VLine2D(Context2D *ctx, I64 x, I64 y, I64 y2, U32 color)
|
||||
{ //Draw a vertical line.
|
||||
if (y2<y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (y<y2+1)
|
||||
{
|
||||
Plot2D(ctx, x, y, color);
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Blot2D(Context2D *dst, I64 x, I64 y, Context2D *src, U32 color=NULL)
|
||||
{
|
||||
if (src==NULL || dst==NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
U8 *chk_alpha_ptr;
|
||||
U32 chk_alpha;
|
||||
U64 i=dst->fb;
|
||||
U64 j=src->fb;
|
||||
I64 xx,yy;
|
||||
I64 dx,sx;
|
||||
i+=(x*dst->bpp/8)+((dst->width*y)*dst->bpp/8);
|
||||
for (yy=0; yy<src->height; yy++)
|
||||
{
|
||||
dx=0;
|
||||
sx=0;
|
||||
for (xx=0; xx<src->width; xx++)
|
||||
{
|
||||
chk_alpha_ptr=j+dx+((src->width*yy)*src->bpp/8);
|
||||
chk_alpha=0;
|
||||
chk_alpha.u8[1]=chk_alpha_ptr[0];
|
||||
chk_alpha.u8[2]=chk_alpha_ptr[1];
|
||||
chk_alpha.u8[3]=chk_alpha_ptr[2];
|
||||
|
||||
if ((chk_alpha!=src->alpha_color || src->alpha_color==-1) &&
|
||||
x+xx>-1 && y+yy>-1 &&
|
||||
x+xx<dst->width && y+yy<dst->height)
|
||||
{
|
||||
if (!color)
|
||||
{
|
||||
MemCpy(i+sx+((dst->width*yy)*dst->bpp/8), j+dx+((src->width*yy)*src->bpp/8), 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemSet(i+sx+((dst->width*yy)*dst->bpp/8), color.u8[1], 1);
|
||||
MemSet(i+sx+((dst->width*yy)*dst->bpp/8)+1, color.u8[2], 1);
|
||||
MemSet(i+sx+((dst->width*yy)*dst->bpp/8)+2, color.u8[3], 1);
|
||||
}
|
||||
}
|
||||
switch (dst->bpp)
|
||||
{
|
||||
case 32:
|
||||
dx+=4;
|
||||
break;
|
||||
case 24:
|
||||
dx+=3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (src->bpp)
|
||||
{
|
||||
case 32:
|
||||
sx+=4;
|
||||
break;
|
||||
case 24:
|
||||
sx+=3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 CopyRect2D(Context2D *ctx, I64 x, I64 y, Context2D *rect)
|
||||
{//Copy rect with clipping.
|
||||
|
||||
U8 *ctx_pos=ctx->fb;
|
||||
U8 *rect_pos=rect->fb;
|
||||
I64 rect_row=0;
|
||||
I64 rect_y_ofs=0;
|
||||
I64 rect_x_ofs=0;
|
||||
I64 clip_y=0;
|
||||
U8 *rect_line;
|
||||
|
||||
//Handle horizontal clipping left
|
||||
while (x<0) { rect_x_ofs++; x++; }
|
||||
|
||||
//Handle vertical clipping top
|
||||
while (y<0)
|
||||
{
|
||||
rect_pos+=(rect->width)*(display.bpp/8);
|
||||
rect_y_ofs++; y++;
|
||||
}
|
||||
|
||||
// default, clip line to copy as width-left off screen
|
||||
rect_line=rect->width-rect_x_ofs;
|
||||
|
||||
if (-rect_x_ofs+x+rect->width>=ctx->width)
|
||||
{
|
||||
rect_line-=((-rect_x_ofs+x+rect->width)-ctx->width);
|
||||
}
|
||||
|
||||
rect_pos+=(rect_x_ofs)*(display.bpp/8);
|
||||
clip_y = y;
|
||||
while (rect_row<(rect->height-rect_y_ofs) && clip_y<ctx->height)
|
||||
{
|
||||
MemCpy(ctx_pos+(y*((ctx->width)*(display.bpp/8)))+x*(display.bpp/8),rect_pos,(rect_line)*(display.bpp/8));
|
||||
ctx_pos+=(ctx->width)*(display.bpp/8);
|
||||
rect_pos+=(rect->width)*(display.bpp/8);
|
||||
clip_y++;
|
||||
rect_row++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Rect2D(Context2D *ctx, I64 x, I64 y, I64 w, I64 h, U32 color)
|
||||
{ //Draw a rectangle fill.
|
||||
Context2D *tmpctx=NewContext2D(Max(4, w), Max(4, h), display.bpp);
|
||||
Fill2D(tmpctx, color);
|
||||
//Blot2D(ctx, x, y, tmpctx);
|
||||
CopyRect2D(ctx, x, y, tmpctx);
|
||||
DelContext2D(tmpctx);
|
||||
}
|
||||
|
||||
Context2D *sys_fb = CAlloc(sizeof(Context2D));
|
||||
|
||||
U0 SysFrameBufferInit()
|
||||
{ //Init values for Context2D alias to system framebuffer.
|
||||
sys_fb->width = display.width;
|
||||
sys_fb->height = display.height;
|
||||
sys_fb->bpp = display.bpp;
|
||||
sys_fb->alpha_color = -1;
|
||||
sys_fb->fb = svga.fb;
|
||||
}
|
||||
|
||||
U0 Flip2D(Context2D *ctx)
|
||||
{
|
||||
MemCpy(sys_fb->fb, ctx->fb, (display.width*display.height)*display.bpp/8);
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
extern I64 frames;
|
||||
extern U0 Print2D(Context2D *ctx, I64 x, I64 y, U32 fg=0xFFFFFFFF, U32 bg=0, U8 *fmt,...);
|
||||
|
||||
Bool cond(I64 val, I64 if_true, I64 if_false)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
return if_true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return if_false;
|
||||
}
|
||||
}
|
||||
|
||||
Bool KeyDown(I64 sc)
|
||||
{
|
||||
return Bt(kbd.down_bitmap, sc);
|
||||
}
|
||||
|
||||
U64 append(U64 str)
|
||||
{
|
||||
return str+StrLen(str);
|
||||
}
|
||||
|
||||
|
||||
I64 fps_frames = frames;
|
||||
I64 fps_jiffies = cnts.jiffies;
|
||||
|
||||
U0 UpdateTOSMenuBar(Context2D *ctx)
|
||||
{
|
||||
if (cnts.jiffies>=fps_jiffies+1000)
|
||||
{
|
||||
winmgr.fps = frames-fps_frames;
|
||||
fps_frames = frames;
|
||||
fps_jiffies = cnts.jiffies;
|
||||
}
|
||||
U8 *st;
|
||||
CCPU *c;
|
||||
I64 i;
|
||||
*wall->top_line=NULL;
|
||||
WallPaper(Fs);
|
||||
Rect2D(ctx, 0, 0, 640, 8, 0x0000a800);
|
||||
Print2D(ctx, 0, 0,,0x0000a800, wall->top_line);
|
||||
WinCalcIdles;
|
||||
for (i=0;i<mp_cnt;i++) {
|
||||
c=&cpu_structs[i];
|
||||
if (i&1)
|
||||
Print2D(ctx, 8*44+(8*(i*2)), 0,,0x0000a800, "%2tf",100.0*(1.0-c->idle_factor));
|
||||
else
|
||||
Print2D(ctx, 8*44+(8*(i*2)), 0,0xffff5700,0x0000a800, "%2tf",100.0*(1.0-c->idle_factor));
|
||||
}
|
||||
st=ScanCode2KeyName(kbd.last_down_scan_code);
|
||||
Print2D(ctx,640-(18*8),0,0xffff5700,0x0000a800,"%18ts",st);
|
||||
Free(st);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
class CVMSVGAInfo
|
||||
{
|
||||
U16 io_base;
|
||||
U16 width;
|
||||
U16 height;
|
||||
U16 bpp;
|
||||
U64 fb;
|
||||
};
|
||||
|
||||
#define VBE_IOPORT_INDEX 0x01CE
|
||||
#define VBE_IOPORT_DATA 0x01CF
|
||||
#define VBE_XRES 1
|
||||
#define VBE_YRES 2
|
||||
#define VBE_BPP 3
|
||||
#define VBE_ENABLE 4
|
||||
|
||||
#define VMSR_FB 13
|
||||
|
||||
CVMSVGAInfo svga;
|
||||
MemSet(&svga, 0, sizeof(CVMSVGAInfo));
|
||||
|
||||
U16 VBE_RegRead(U16 index)
|
||||
{
|
||||
OutU16(VBE_IOPORT_INDEX, index);
|
||||
return InU16(VBE_IOPORT_DATA);
|
||||
}
|
||||
|
||||
U0 VBE_RegWrite(U16 index, U16 val)
|
||||
{
|
||||
OutU16(VBE_IOPORT_INDEX, index);
|
||||
OutU16(VBE_IOPORT_DATA, val);
|
||||
}
|
||||
|
||||
U32 VMSVGA_RegRead(I64 index)
|
||||
{
|
||||
OutU32(svga.io_base, index);
|
||||
return InU32(svga.io_base+1);
|
||||
}
|
||||
|
||||
U0 VMSVGA_RegWrite(I64 index, U32 val)
|
||||
{
|
||||
OutU32(svga.io_base, index);
|
||||
OutU32(svga.io_base+1, val);
|
||||
}
|
||||
|
||||
U0 GetVideoRegVals()
|
||||
{
|
||||
svga.width = VBE_RegRead(VBE_XRES);
|
||||
svga.height = VBE_RegRead(VBE_YRES);
|
||||
svga.bpp = VBE_RegRead(VBE_BPP);
|
||||
svga.fb = VMSVGA_RegRead(VMSR_FB);
|
||||
}
|
||||
|
||||
U0 SetVideoRegVals()
|
||||
{
|
||||
VBE_RegWrite(VBE_ENABLE, 0);
|
||||
VBE_RegWrite(VBE_XRES, svga.width);
|
||||
VBE_RegWrite(VBE_YRES, svga.height);
|
||||
VBE_RegWrite(VBE_BPP, svga.bpp);
|
||||
VBE_RegWrite(VBE_ENABLE, 1);
|
||||
}
|
||||
|
||||
U0 VMSVGA_Start(I64 w=640,I64 h=480,I64 bpp=32)
|
||||
{
|
||||
switch (bpp)
|
||||
{
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
"\nInvalid bpp. (must be 32)\n";
|
||||
return;
|
||||
break;
|
||||
}
|
||||
I64 j;
|
||||
//Scan for device
|
||||
j=PCIClassFind(0x030000,0);
|
||||
if (j<0)
|
||||
{
|
||||
"\nVMSVGA device not found.\n";
|
||||
return;
|
||||
}
|
||||
svga.io_base=PCIReadU16(j.u8[2],
|
||||
j.u8[1],j.u8[0],0x10) & ~(0x0F);
|
||||
if (!svga.io_base)
|
||||
{
|
||||
"\nError reading base I/O address.\n";
|
||||
return;
|
||||
}
|
||||
GetVideoRegVals;
|
||||
svga.width=w;
|
||||
svga.height=h;
|
||||
svga.bpp=bpp;
|
||||
LBts(&sys_winmgr_task->task_flags,TASKf_SUSPENDED);
|
||||
//Raw(ON);
|
||||
SetVideoRegVals;
|
||||
}
|
||||
+1073
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
U0 parseHeader(U8 *rom, ROMHeader *header)
|
||||
{
|
||||
I64 i;
|
||||
header->name = CAlloc(24);
|
||||
MemCpy(header->name, rom+0x7FC0, 20);
|
||||
i = StrLen(header->name)-1;
|
||||
while (header->name[i]==' ') { header->name[i]=NULL; i--; }
|
||||
header->type = rom[0x7fd5] & 0xf;
|
||||
header->speed = rom[0x7fd5] >> 4;
|
||||
header->chips = rom[0x7fd6];
|
||||
header->romSize = 0x400 << rom[0x7fd7];
|
||||
header->ramSize = 0x400 << rom[0x7fd8];
|
||||
header->hasSram = header->chips > 0;
|
||||
header->banks = header->romSize / 0x8000;
|
||||
header->sramSize = cond(header->hasSram, header->ramSize, 0);
|
||||
if (header->hasSram) sram = MAlloc(header->ramSize);
|
||||
}
|
||||
|
||||
U0 LoROM(U8 *filename)
|
||||
{
|
||||
|
||||
// LoROM loader
|
||||
MemSet(&header, NULL, sizeof(ROMHeader));
|
||||
I64 rom_length;
|
||||
rom = FileRead(filename, &rom_length);
|
||||
|
||||
// skip copier header
|
||||
if (rom_length%1024)
|
||||
{
|
||||
rom += 512;
|
||||
rom_length -= 512;
|
||||
}
|
||||
|
||||
parseHeader(rom, &header);
|
||||
|
||||
if (header.romSize < rom_length)
|
||||
{
|
||||
"Incorrect romSize?\n";
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "Lib/VMSVGA";
|
||||
#include "Lib/Display";
|
||||
#include "Lib/Graphics2D";
|
||||
#include "Lib/uPNG";
|
||||
|
||||
#include "Lib/Misc";
|
||||
|
||||
#include "Lib/Debugger";
|
||||
|
||||
Context2D *screen_ctx = NewContext2D(640, 480, 32);
|
||||
Context2D *pixel_ctx = NewContext2D(512, 480, 32);
|
||||
|
||||
#include "Font";
|
||||
#include "Snes";
|
||||
#include "LoROM";
|
||||
|
||||
#include "MMU";
|
||||
#include "CPU";
|
||||
#include "PPU";
|
||||
|
||||
U0 cpu_task()
|
||||
{
|
||||
while (1) { if (!Debug && !KeyDown(SC_F1)) cycle(0); };
|
||||
}
|
||||
|
||||
U0 gfx_task()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (yPos>238 && !Debug)
|
||||
{
|
||||
setPixels(pixel_ctx->fb);
|
||||
CopyRect2D(screen_ctx, (screen_ctx->width/2)-(pixel_ctx->width/2), 0, pixel_ctx);
|
||||
UpdateTOSMenuBar(screen_ctx);
|
||||
Flip2D(screen_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 input_loop()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
WinMsUpdate;
|
||||
KbdMsHndlr(0, 0);
|
||||
if (KeyDown(SC_ESC))
|
||||
{
|
||||
FifoI64Flush(kbd.down_bitmap);
|
||||
Debug = TRUE;
|
||||
Dbg;
|
||||
}
|
||||
if (KeyDown(Char2ScanCode('`')))
|
||||
{
|
||||
cpu_reset;
|
||||
ppu_reset;
|
||||
}
|
||||
Joypad1Update;
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
U0 LoadCart(U8 *filename)
|
||||
{
|
||||
// FIXME: Add sanity checks
|
||||
LoROM(filename);
|
||||
U8 *info_string=CAlloc(1024);
|
||||
|
||||
StrPrint(append(info_string), "Loaded ROM: \"%s\"; \n", header.name);
|
||||
StrPrint(append(info_string), "Type: LoROM\n");
|
||||
StrPrint(append(info_string), "Banks: %d; Sram size: 0x%04X\n", header.banks, header.sramSize);
|
||||
PopUpOk(info_string);
|
||||
|
||||
VMSVGA_Start;
|
||||
SysFrameBufferInit;
|
||||
|
||||
cpu_reset;
|
||||
|
||||
Spawn(&cpu_task,,,1);
|
||||
Spawn(&gfx_task,,,2);
|
||||
|
||||
input_loop;
|
||||
Free(info_string);
|
||||
}
|
||||
|
||||
U0 Bahamut(U8 *filename)
|
||||
{
|
||||
if (IsDir(filename))
|
||||
{
|
||||
PopUpOk("That's a directory...");
|
||||
return;
|
||||
}
|
||||
CDirEntry *file = FilesFind(filename);
|
||||
if (file)
|
||||
{
|
||||
DirTreeDel(file);
|
||||
LoadCart(filename);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PopUpOk("File not found...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) Bahamut(PopUpPickFile("T:/ROMs/"));
|
||||
@@ -0,0 +1,436 @@
|
||||
extern U16 br[6];
|
||||
|
||||
extern I32 ppu_read(I32 adr);
|
||||
extern U0 ppu_write(I32 adr, I32 value);
|
||||
|
||||
I64 cart_read(I64 bank, I64 adr)
|
||||
{
|
||||
//"bank: %d, addr: %08X\n", bank, adr;
|
||||
if(adr < 0x8000) {
|
||||
if(bank >= 0x70 && bank < 0x7e && header.hasSram) {
|
||||
// sram
|
||||
return sram[
|
||||
(((bank - 0x70) << 15) | (adr & 0x7fff)) & (header.sramSize - 1)
|
||||
];
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return rom[((bank & (header.banks - 1)) << 15) | (adr & 0x7fff)];
|
||||
}
|
||||
|
||||
U0 cart_write(I64 bank, I64 adr, I64 value)
|
||||
{
|
||||
if(adr < 0x8000 && bank >= 0x70 && bank < 0x7e && header.hasSram) {
|
||||
sram[
|
||||
(((bank - 0x70) << 15) | (adr & 0x7fff)) & (header.sramSize - 1)
|
||||
] = value;
|
||||
}
|
||||
}
|
||||
|
||||
I64 readReg(I64 adr)
|
||||
{
|
||||
I64 val;
|
||||
switch(adr) {
|
||||
case 0x4210: {
|
||||
val = 0x1;
|
||||
val |= cond(inNmi, 0x80, 0);
|
||||
val |= openBus & 0x70;
|
||||
inNmi = FALSE;
|
||||
return val;
|
||||
}
|
||||
case 0x4211: {
|
||||
val = cond(inIrq, 0x80, 0);
|
||||
val |= openBus & 0x7f;
|
||||
inIrq = FALSE;
|
||||
irqWanted = FALSE;
|
||||
return val;
|
||||
}
|
||||
case 0x4212: {
|
||||
val = cond(autoJoyBusy, 0x1, 0);
|
||||
val |= cond(inHblank, 0x40, 0);
|
||||
val |= cond(inVblank, 0x80, 0);
|
||||
val |= openBus & 0x3e;
|
||||
return val;
|
||||
}
|
||||
case 0x4213: {
|
||||
// IO read register
|
||||
return cond(ppuLatch, 0x80, 0);
|
||||
}
|
||||
case 0x4214: {
|
||||
return divResult & 0xff;
|
||||
}
|
||||
case 0x4215: {
|
||||
return (divResult & 0xff00) >> 8;
|
||||
}
|
||||
case 0x4216: {
|
||||
return mulResult & 0xff;
|
||||
}
|
||||
case 0x4217: {
|
||||
return (mulResult & 0xff00) >> 8;
|
||||
}
|
||||
case 0x4218: {
|
||||
return joypad1AutoRead & 0xff;
|
||||
}
|
||||
case 0x4219: {
|
||||
return (joypad1AutoRead & 0xff00) >> 8;
|
||||
}
|
||||
case 0x421a: {
|
||||
return joypad2AutoRead & 0xff;
|
||||
}
|
||||
case 0x421b: {
|
||||
return (joypad2AutoRead & 0xff00) >> 8;
|
||||
}
|
||||
case 0x421c:
|
||||
case 0x421d:
|
||||
case 0x421e:
|
||||
case 0x421f: {
|
||||
// joypads 3 and 4 not emulated
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(adr >= 0x4300 && adr < 0x4380) {
|
||||
I64 channel = (adr & 0xf0) >> 4;
|
||||
switch(adr & 0xff0f) {
|
||||
case 0x4300: {
|
||||
val = dmaMode[channel];
|
||||
val |= cond(dmaFixed[channel], 0x8, 0);
|
||||
val |= cond(dmaDec[channel], 0x10, 0);
|
||||
val |= cond(hdmaInd[channel], 0x40, 0);
|
||||
val |= cond(dmaFromB[channel], 0x80, 0);
|
||||
return val;
|
||||
}
|
||||
case 0x4301: {
|
||||
return dmaBadr[channel];
|
||||
}
|
||||
case 0x4302: {
|
||||
return dmaAadr[channel] & 0xff;
|
||||
}
|
||||
case 0x4303: {
|
||||
return (dmaAadr[channel] & 0xff00) >> 8;
|
||||
}
|
||||
case 0x4304: {
|
||||
return dmaAadrBank[channel];
|
||||
}
|
||||
case 0x4305: {
|
||||
return dmaSize[channel] & 0xff;
|
||||
}
|
||||
case 0x4306: {
|
||||
return (dmaSize[channel] & 0xff00) >> 8;
|
||||
}
|
||||
case 0x4307: {
|
||||
return hdmaIndBank[channel];
|
||||
}
|
||||
case 0x4308: {
|
||||
return hdmaTableAdr[channel] & 0xff;
|
||||
}
|
||||
case 0x4309: {
|
||||
return (hdmaTableAdr[channel] & 0xff00) >> 8;
|
||||
}
|
||||
case 0x430a: {
|
||||
return hdmaRepCount[channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return openBus;
|
||||
}
|
||||
|
||||
U0 writeReg(I64 adr, I64 value) {
|
||||
I64 channel;
|
||||
switch(adr) {
|
||||
case 0x4200: {
|
||||
autoJoyRead = (value & 0x1) > 0;
|
||||
hIrqEnabled = (value & 0x10) > 0;
|
||||
vIrqEnabled = (value & 0x20) > 0;
|
||||
nmiEnabled = (value & 0x80) > 0;
|
||||
return;
|
||||
}
|
||||
case 0x4201: {
|
||||
// IO port
|
||||
if(ppuLatch && (value & 0x80) == 0) {
|
||||
latchedHpos = xPos >> 2;
|
||||
latchedVpos = yPos;
|
||||
countersLatched = TRUE;
|
||||
}
|
||||
ppuLatch = (value & 0x80) > 0;
|
||||
return;
|
||||
}
|
||||
case 0x4202: {
|
||||
multiplyA = value;
|
||||
return;
|
||||
}
|
||||
case 0x4203: {
|
||||
mulResult = multiplyA * value;
|
||||
return;
|
||||
}
|
||||
case 0x4204: {
|
||||
divA = (divA & 0xff00) | value;
|
||||
return;
|
||||
}
|
||||
case 0x4205: {
|
||||
divA = (divA & 0xff) | (value << 8);
|
||||
return;
|
||||
}
|
||||
case 0x4206: {
|
||||
divResult = 0xffff;
|
||||
mulResult = divA;
|
||||
if(value != 0) {
|
||||
divResult = (divA / value) & 0xffff;
|
||||
mulResult = divA % value;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 0x4207: {
|
||||
hTimer = (hTimer & 0x100) | value;
|
||||
return;
|
||||
}
|
||||
case 0x4208: {
|
||||
hTimer = (hTimer & 0xff) | ((value & 0x1) << 8);
|
||||
return;
|
||||
}
|
||||
case 0x4209: {
|
||||
vTimer = (vTimer & 0x100) | value;
|
||||
return;
|
||||
}
|
||||
case 0x420a: {
|
||||
vTimer = (vTimer & 0xff) | ((value & 0x1) << 8);
|
||||
return;
|
||||
}
|
||||
case 0x420b: {
|
||||
// enable dma
|
||||
dmaActive[0] = (value & 0x1) > 0;
|
||||
dmaActive[1] = (value & 0x2) > 0;
|
||||
dmaActive[2] = (value & 0x4) > 0;
|
||||
dmaActive[3] = (value & 0x8) > 0;
|
||||
dmaActive[4] = (value & 0x10) > 0;
|
||||
dmaActive[5] = (value & 0x20) > 0;
|
||||
dmaActive[6] = (value & 0x40) > 0;
|
||||
dmaActive[7] = (value & 0x80) > 0;
|
||||
dmaBusy = value > 0;
|
||||
dmaTimer += cond(dmaBusy, 8, 0);
|
||||
return;
|
||||
}
|
||||
case 0x420c: {
|
||||
hdmaActive[0] = (value & 0x1) > 0;
|
||||
hdmaActive[1] = (value & 0x2) > 0;
|
||||
hdmaActive[2] = (value & 0x4) > 0;
|
||||
hdmaActive[3] = (value & 0x8) > 0;
|
||||
hdmaActive[4] = (value & 0x10) > 0;
|
||||
hdmaActive[5] = (value & 0x20) > 0;
|
||||
hdmaActive[6] = (value & 0x40) > 0;
|
||||
hdmaActive[7] = (value & 0x80) > 0;
|
||||
return;
|
||||
}
|
||||
case 0x420d: {
|
||||
fastMem = (value & 0x1) > 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(adr >= 0x4300 && adr < 0x4380) {
|
||||
channel = (adr & 0xf0) >> 4;
|
||||
switch(adr & 0xff0f) {
|
||||
case 0x4300: {
|
||||
dmaMode[channel] = value & 0x7;
|
||||
dmaFixed[channel] = (value & 0x08) > 0;
|
||||
dmaDec[channel] = (value & 0x10) > 0;
|
||||
hdmaInd[channel] = (value & 0x40) > 0;
|
||||
dmaFromB[channel] = (value & 0x80) > 0;
|
||||
return;
|
||||
}
|
||||
case 0x4301: {
|
||||
dmaBadr[channel] = value;
|
||||
return;
|
||||
}
|
||||
case 0x4302: {
|
||||
dmaAadr[channel] = (dmaAadr[channel] & 0xff00) | value;
|
||||
return;
|
||||
}
|
||||
case 0x4303: {
|
||||
dmaAadr[channel] = (dmaAadr[channel] & 0xff) | (value << 8);
|
||||
return;
|
||||
}
|
||||
case 0x4304: {
|
||||
dmaAadrBank[channel] = value;
|
||||
return;
|
||||
}
|
||||
case 0x4305: {
|
||||
dmaSize[channel] = (dmaSize[channel] & 0xff00) | value;
|
||||
return;
|
||||
}
|
||||
case 0x4306: {
|
||||
dmaSize[channel] = (dmaSize[channel] & 0xff) | (value << 8);
|
||||
return;
|
||||
}
|
||||
case 0x4307: {
|
||||
hdmaIndBank[channel] = value;
|
||||
return;
|
||||
}
|
||||
case 0x4308: {
|
||||
hdmaTableAdr[channel] = (
|
||||
hdmaTableAdr[channel] & 0xff00
|
||||
) | value;
|
||||
return;
|
||||
}
|
||||
case 0x4309: {
|
||||
hdmaTableAdr[channel] = (
|
||||
hdmaTableAdr[channel] & 0xff
|
||||
) | (value << 8);
|
||||
return;
|
||||
}
|
||||
case 0x430a: {
|
||||
hdmaRepCount[channel] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bool flip_fake_spc = FALSE; // FIXME: Implement sound emulation
|
||||
|
||||
I64 readBBus(I64 adr) {
|
||||
I64 val;
|
||||
if(adr > 0x33 && adr < 0x40) {
|
||||
return ppu_read(adr);
|
||||
}
|
||||
if(adr >= 0x40 && adr < 0x80) {
|
||||
// catch up the apu, then do the read
|
||||
catchUpApu;
|
||||
// FIXME: Implement sound emulation
|
||||
if (flip_fake_spc) return br[0];
|
||||
flip_fake_spc = !flip_fake_spc;
|
||||
return 0xBBAA;
|
||||
//return spcWritePorts[adr & 0x3];
|
||||
}
|
||||
if(adr == 0x80) {
|
||||
val = ram[ramAdr++];
|
||||
ramAdr &= 0x1ffff;
|
||||
return val;
|
||||
}
|
||||
return openBus; // rest not readable
|
||||
}
|
||||
|
||||
U0 writeBBus(I64 adr, I64 value) {
|
||||
if(adr < 0x34) {
|
||||
ppu_write(adr, value);
|
||||
return;
|
||||
}
|
||||
if(adr >= 0x40 && adr < 0x80) {
|
||||
// catch up the apu, then do the write
|
||||
catchUpApu;
|
||||
spcReadPorts[adr & 0x3] = value;
|
||||
return;
|
||||
}
|
||||
switch(adr) {
|
||||
case 0x80: {
|
||||
ram[ramAdr++] = value;
|
||||
ramAdr &= 0x1ffff;
|
||||
return;
|
||||
}
|
||||
case 0x81: {
|
||||
ramAdr = (ramAdr & 0x1ff00) | value;
|
||||
return;
|
||||
}
|
||||
case 0x82: {
|
||||
ramAdr = (ramAdr & 0x100ff) | (value << 8);
|
||||
return;
|
||||
}
|
||||
case 0x83: {
|
||||
ramAdr = (ramAdr & 0x0ffff) | ((value & 1) << 16);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
I64 mem_rread(I64 adr)
|
||||
{
|
||||
I64 val;
|
||||
adr &= 0xffffff;
|
||||
I64 bank = adr >> 16;
|
||||
adr &= 0xffff;
|
||||
|
||||
if(bank == 0x7e || bank == 0x7f) {
|
||||
// banks 7e and 7f
|
||||
return ram[((bank & 0x1) << 16) | adr];
|
||||
return NULL;
|
||||
}
|
||||
if(adr < 0x8000 && (bank < 0x40 || (bank >= 0x80 && bank < 0xc0))) {
|
||||
// banks 00-3f, 80-bf, $0000-$7fff
|
||||
if(adr < 0x2000) {
|
||||
return ram[adr & 0x1fff];
|
||||
return NULL;
|
||||
}
|
||||
if(adr >= 0x2100 && adr < 0x2200) {
|
||||
return readBBus(adr & 0xff);
|
||||
return NULL;
|
||||
}
|
||||
// old-style controller reads
|
||||
if(adr == 0x4016) {
|
||||
val = joypad1Val & 0x1;
|
||||
joypad1Val >>= 1;
|
||||
joypad1Val |= 0x8000;
|
||||
return val;
|
||||
}
|
||||
if(adr == 0x4017) {
|
||||
val = joypad2Val & 0x1;
|
||||
joypad2Val >>= 1;
|
||||
joypad2Val |= 0x8000;
|
||||
return val;
|
||||
}
|
||||
if(adr >= 0x4200 && adr < 0x4400) {
|
||||
return readReg(adr);
|
||||
}
|
||||
|
||||
return openBus; // not readable
|
||||
}
|
||||
return cart_read(bank, adr);
|
||||
}
|
||||
|
||||
I64 mem_read(I64 adr, Bool dma=FALSE)
|
||||
{
|
||||
if(!dma) {
|
||||
cpuMemOps++;
|
||||
cpuCyclesLeft += getAccessTime(adr);
|
||||
}
|
||||
|
||||
I64 val = mem_rread(adr);
|
||||
openBus = val;
|
||||
return val;
|
||||
}
|
||||
|
||||
U0 mem_write(I64 adr, I64 value, Bool dma = FALSE) {
|
||||
if(!dma) {
|
||||
cpuMemOps++;
|
||||
cpuCyclesLeft += getAccessTime(adr);
|
||||
}
|
||||
|
||||
openBus = value;
|
||||
adr &= 0xffffff;
|
||||
//log("Written $" + getByteRep(value) + " to $" + getLongRep(adr));
|
||||
I64 bank = adr >> 16;
|
||||
adr &= 0xffff;
|
||||
if(bank == 0x7e || bank == 0x7f) {
|
||||
// banks 7e and 7f
|
||||
ram[((bank & 0x1) << 16) | adr] = value;
|
||||
}
|
||||
if(adr < 0x8000 && (bank < 0x40 || (bank >= 0x80 && bank < 0xc0))) {
|
||||
// banks 00-3f, 80-bf, $0000-$7fff
|
||||
if(adr < 0x2000) {
|
||||
ram[adr & 0x1fff] = value;
|
||||
}
|
||||
if(adr >= 0x2100 && adr < 0x2200) {
|
||||
writeBBus(adr & 0xff, value);
|
||||
}
|
||||
if(adr == 0x4016) {
|
||||
joypadStrobe = (value & 0x1) > 0;
|
||||
}
|
||||
if(adr >= 0x4200 && adr < 0x4400) {
|
||||
writeReg(adr, value);
|
||||
}
|
||||
|
||||
}
|
||||
cart_write(bank, adr, value);
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
extern I64 mem_read(I64 adr, Bool dma=FALSE);
|
||||
extern U0 mem_write(I64 adr, I64 value, Bool dma = FALSE);
|
||||
extern I64 readBBus(I64 adr);
|
||||
extern U0 writeBBus(I64 adr, I64 value);
|
||||
extern U0 cpu_cycle();
|
||||
extern U0 renderLine(I32 line);
|
||||
|
||||
class ROMHeader
|
||||
{
|
||||
U8 *name;
|
||||
I64 type;
|
||||
I64 speed;
|
||||
I64 chips;
|
||||
I64 romSize;
|
||||
I64 ramSize;
|
||||
Bool hasSram;
|
||||
I64 banks;
|
||||
I64 sramSize;
|
||||
};
|
||||
ROMHeader header;
|
||||
|
||||
U8 *ram = MAlloc(0x20000);
|
||||
U8 *sram;
|
||||
U8 *rom;
|
||||
|
||||
|
||||
// ppu variables
|
||||
I64 cgramAdr;
|
||||
Bool cgramSecond;
|
||||
I64 cgramBuffer = 0;
|
||||
I64 vramInc;
|
||||
I64 vramRemap;
|
||||
Bool vramIncOnHigh;
|
||||
I64 vramAdr;
|
||||
I64 vramReadBuffer;
|
||||
Bool tilemapWider[4];
|
||||
Bool tilemapHigher[4];
|
||||
I64 tilemapAdr[4];
|
||||
I64 tileAdr[4];
|
||||
I64 bgHoff[5];
|
||||
I64 bgVoff[5];
|
||||
I64 offPrev1;
|
||||
I64 offPrev2;
|
||||
I64 mode;
|
||||
Bool layer3Prio;
|
||||
Bool bigTiles[4];
|
||||
Bool mosaicEnabled[5];
|
||||
I64 mosaicSize;
|
||||
I64 mosaicStartLine;
|
||||
Bool mainScreenEnabled[5];
|
||||
Bool subScreenEnabled[5];
|
||||
Bool forcedBlank;
|
||||
I64 brightness;
|
||||
I64 oamAdr;
|
||||
I64 oamRegAdr;
|
||||
Bool oamInHigh;
|
||||
Bool oamRegInHigh;
|
||||
Bool objPriority;
|
||||
Bool oamSecond;
|
||||
U16 oamBuffer;
|
||||
I64 sprAdr1;
|
||||
I64 sprAdr2;
|
||||
I64 objSize;
|
||||
Bool rangeOver;
|
||||
Bool timeOver;
|
||||
Bool mode7ExBg;
|
||||
Bool pseudoHires;
|
||||
Bool overscan;
|
||||
Bool objInterlace;
|
||||
Bool interlace;
|
||||
Bool frameOverscan;
|
||||
Bool frameInterlace;
|
||||
Bool evenFrame;
|
||||
I64 latchedHpos;
|
||||
I64 latchedVpos;
|
||||
Bool latchHsecond;
|
||||
Bool latchVsecond;
|
||||
Bool countersLatched;
|
||||
I64 mode7Hoff;
|
||||
I64 mode7Voff;
|
||||
I64 mode7A;
|
||||
I64 mode7B;
|
||||
I64 mode7C;
|
||||
I64 mode7D;
|
||||
I64 mode7X;
|
||||
I64 mode7Y;
|
||||
I64 mode7Prev;
|
||||
I64 multResult;
|
||||
Bool mode7LargeField;
|
||||
Bool mode7Char0fill;
|
||||
Bool mode7FlipX;
|
||||
Bool mode7FlipY;
|
||||
Bool window1Inversed[6];
|
||||
Bool window1Enabled[6];
|
||||
Bool window2Inversed[6];
|
||||
Bool window2Enabled[6];
|
||||
I64 windowMaskLogic[6];
|
||||
I64 window1Left;
|
||||
I64 window1Right;
|
||||
I64 window2Left;
|
||||
I64 window2Right;
|
||||
Bool mainScreenWindow[6];
|
||||
Bool subScreenWindow[6];
|
||||
I64 colorClip;
|
||||
I64 preventMath;
|
||||
Bool addSub;
|
||||
Bool directColor;
|
||||
Bool subtractColors;
|
||||
Bool halfColors;
|
||||
Bool mathEnabled[6];
|
||||
I64 fixedColorB;
|
||||
I64 fixedColorG;
|
||||
I64 fixedColorR;
|
||||
I64 tilemapBuffer[4];
|
||||
I64 tileBufferP1[4];
|
||||
I64 tileBufferP2[4];
|
||||
I64 tileBufferP3[4];
|
||||
I64 tileBufferP4[4];
|
||||
I64 lastTileFetchedX[4];
|
||||
I64 lastTileFetchedY[4];
|
||||
I64 optHorBuffer[2];
|
||||
I64 optVerBuffer[2];
|
||||
I64 lastOrigTileX[2];
|
||||
|
||||
I64 dmaOffs[32] = {
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 1,
|
||||
0, 1, 2, 3,
|
||||
0, 1, 0, 1,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 1
|
||||
};
|
||||
|
||||
I64 dmaOffLengths[8] = {1, 2, 2, 4, 4, 4, 2, 4};
|
||||
|
||||
I64 apuCyclesPerMaster = (32040 * 32) / (1364 * 262 * 60);
|
||||
|
||||
U8 spcWritePorts[4];
|
||||
U8 spcReadPorts[6];
|
||||
|
||||
// for dma
|
||||
U8 dmaBadr[8];
|
||||
U16 dmaAadr[8];
|
||||
U8 dmaAadrBank[8];
|
||||
U16 dmaSize[8];
|
||||
U8 hdmaIndBank[8];
|
||||
U16 hdmaTableAdr[8];
|
||||
U8 hdmaRepCount[8];
|
||||
|
||||
I64 xPos = 0;
|
||||
I64 yPos = 0;
|
||||
I64 frames = 0;
|
||||
|
||||
I64 cpuCyclesLeft = 5 * 8 + 12; // reset: 5 read cycles + 2 IO cycles
|
||||
I64 cpuMemOps = 0;
|
||||
I64 apuCatchCycles = 0;
|
||||
|
||||
I64 cyclesLeft; // moved from CPU.HC
|
||||
Bool irqWanted; // moved from CPU.HC
|
||||
Bool nmiWanted; // moved from CPU.HC
|
||||
|
||||
// for cpu-ports
|
||||
I64 ramAdr = 0;
|
||||
|
||||
Bool hIrqEnabled = FALSE;
|
||||
Bool vIrqEnabled = FALSE;
|
||||
Bool nmiEnabled = FALSE;
|
||||
I64 hTimer = 0x1ff;
|
||||
I64 vTimer = 0x1ff;
|
||||
Bool inNmi = FALSE;
|
||||
Bool inIrq = FALSE;
|
||||
Bool inHblank = FALSE;
|
||||
Bool inVblank = FALSE;
|
||||
|
||||
Bool autoJoyRead = FALSE;
|
||||
Bool autoJoyBusy = FALSE;
|
||||
I64 autoJoyTimer = 0;
|
||||
Bool ppuLatch = FALSE;
|
||||
|
||||
I64 joypad1Val = 0;
|
||||
I64 joypad2Val = 0;
|
||||
I64 joypad1AutoRead = 0;
|
||||
I64 joypad2AutoRead = 0;
|
||||
Bool joypadStrobe = FALSE;
|
||||
I64 joypad1State = 0; // current button state
|
||||
I64 joypad2State = 0; // current button state
|
||||
|
||||
I64 multiplyA = 0xff;
|
||||
I64 divA = 0xffff;
|
||||
I64 divResult = 0x101;
|
||||
I64 mulResult = 0xfe01;
|
||||
|
||||
Bool fastMem = FALSE;
|
||||
|
||||
// dma and hdma
|
||||
I64 dmaTimer = 0;
|
||||
I64 hdmaTimer = 0;
|
||||
Bool dmaBusy = FALSE;
|
||||
Bool dmaActive[8] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
|
||||
Bool hdmaActive[8] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
|
||||
|
||||
I64 dmaMode[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
Bool dmaFixed[8] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
|
||||
Bool dmaDec[8] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
|
||||
Bool hdmaInd[8] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
|
||||
Bool dmaFromB[8] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
|
||||
|
||||
Bool hdmaDoTransfer[8] = {
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
Bool hdmaTerminated[8] = {
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
I64 dmaOffIndex = 0;
|
||||
|
||||
I64 openBus = 0;
|
||||
|
||||
I64 getAccessTime(I64 adr) {
|
||||
adr &= 0xffffff;
|
||||
I64 bank = adr >> 16;
|
||||
adr &= 0xffff;
|
||||
if(bank >= 0x40 && bank < 0x80) {
|
||||
// banks 0x40-0x7f, all slow
|
||||
return 8;
|
||||
}
|
||||
if(bank >= 0xc0) {
|
||||
// banks 0xc0-0xff, depends on speed
|
||||
return cond(fastMem, 6, 8);
|
||||
}
|
||||
// banks 0x00-0x3f and 0x80-0xbf
|
||||
if(adr < 0x2000) {
|
||||
return 8; // slow
|
||||
}
|
||||
if(adr < 0x4000) {
|
||||
return 6; // fast
|
||||
}
|
||||
if(adr < 0x4200) {
|
||||
return 12; // extra slow
|
||||
}
|
||||
if(adr < 0x6000) {
|
||||
return 6; // fast
|
||||
}
|
||||
if(adr < 0x8000) {
|
||||
return 8; // slow
|
||||
}
|
||||
// 0x8000-0xffff, depends on fastrom setting if in banks 0x80+
|
||||
return cond((fastMem && bank >= 0x80), 6, 8);
|
||||
|
||||
}
|
||||
|
||||
|
||||
U0 catchUpApu() {
|
||||
I64 i;
|
||||
I64 catchUpCycles = apuCatchCycles & 0xffffffff;
|
||||
for(i = 0; i < catchUpCycles; i++) {
|
||||
//apu_cycle;
|
||||
}
|
||||
apuCatchCycles -= catchUpCycles;
|
||||
}
|
||||
|
||||
U0 handleDma() {
|
||||
I64 i, tableOff;
|
||||
if(dmaTimer > 0) {
|
||||
dmaTimer -= 2;
|
||||
return;
|
||||
}
|
||||
// loop over each dma channel to find the first active one
|
||||
for(i = 0; i < 8; i++) {
|
||||
if(dmaActive[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == 8) {
|
||||
// no active channel left, dma is done
|
||||
dmaBusy = FALSE;
|
||||
dmaOffIndex = 0;
|
||||
//log("Finished DMA");
|
||||
return;
|
||||
}
|
||||
tableOff = dmaMode[i] * 4 + dmaOffIndex++;
|
||||
dmaOffIndex &= 0x3;
|
||||
if(dmaFromB[i]) {
|
||||
mem_write(
|
||||
(dmaAadrBank[i] << 16) | dmaAadr[i],
|
||||
readBBus(
|
||||
(dmaBadr[i] + dmaOffs[tableOff]) & 0xff
|
||||
), TRUE
|
||||
);
|
||||
} else {
|
||||
writeBBus(
|
||||
(dmaBadr[i] + dmaOffs[tableOff]) & 0xff,
|
||||
mem_read((dmaAadrBank[i] << 16) | dmaAadr[i], TRUE)
|
||||
);
|
||||
}
|
||||
dmaTimer += 6;
|
||||
// because this run through the function itself also costs 2 master cycles,
|
||||
// we have to wait 6 more to get to 8 per byte transferred
|
||||
if(!dmaFixed[i]) {
|
||||
if(dmaDec[i]) {
|
||||
dmaAadr[i]--;
|
||||
} else {
|
||||
dmaAadr[i]++;
|
||||
}
|
||||
}
|
||||
dmaSize[i]--;
|
||||
if(dmaSize[i] == 0) {
|
||||
dmaOffIndex = 0;
|
||||
dmaActive[i] = FALSE;
|
||||
dmaTimer += 8; // 8 extra cycles overhead per channel
|
||||
}
|
||||
}
|
||||
|
||||
U0 initHdma() {
|
||||
hdmaTimer = 18;
|
||||
I64 i;
|
||||
for(i = 0; i < 8; i++) {
|
||||
if(hdmaActive[i]) {
|
||||
// terminate DMA if it was busy for this channel
|
||||
dmaActive[i] = FALSE;
|
||||
|
||||
hdmaTableAdr[i] = dmaAadr[i];
|
||||
hdmaRepCount[i] = mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i]++, TRUE
|
||||
);
|
||||
hdmaTimer += 8;
|
||||
if(hdmaInd[i]) {
|
||||
dmaSize[i] = mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i]++, TRUE
|
||||
);
|
||||
dmaSize[i] |= mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i]++, TRUE
|
||||
) << 8;
|
||||
hdmaTimer += 16;
|
||||
}
|
||||
hdmaDoTransfer[i] = TRUE;
|
||||
} else {
|
||||
hdmaDoTransfer[i] = FALSE;
|
||||
}
|
||||
hdmaTerminated[i] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 handleHdma() {
|
||||
I64 i, j, tableOff;
|
||||
hdmaTimer = 18;
|
||||
for(i = 0; i < 8; i++) {
|
||||
if(hdmaActive[i] && !hdmaTerminated[i]) {
|
||||
// terminate dma if it is busy on this channel
|
||||
dmaActive[i] = FALSE;
|
||||
hdmaTimer += 8;
|
||||
if(hdmaDoTransfer[i]) {
|
||||
for(j = 0; j < dmaOffLengths[dmaMode[i]]; j++) {
|
||||
tableOff = dmaMode[i] * 4 + j;
|
||||
hdmaTimer += 8;
|
||||
if(hdmaInd[i]) {
|
||||
if(dmaFromB[i]) {
|
||||
mem_write(
|
||||
(hdmaIndBank[i] << 16) | dmaSize[i],
|
||||
readBBus(
|
||||
(dmaBadr[i] + dmaOffs[tableOff]) & 0xff
|
||||
), TRUE
|
||||
);
|
||||
} else {
|
||||
writeBBus(
|
||||
(dmaBadr[i] + dmaOffs[tableOff]) & 0xff,
|
||||
mem_read((hdmaIndBank[i] << 16) | dmaSize[i], TRUE)
|
||||
);
|
||||
}
|
||||
dmaSize[i]++;
|
||||
} else {
|
||||
if(dmaFromB[i]) {
|
||||
mem_write(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i],
|
||||
readBBus(
|
||||
(dmaBadr[i] + dmaOffs[tableOff]) & 0xff
|
||||
), TRUE
|
||||
);
|
||||
} else {
|
||||
writeBBus(
|
||||
(dmaBadr[i] + dmaOffs[tableOff]) & 0xff,
|
||||
mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i], TRUE
|
||||
)
|
||||
);
|
||||
}
|
||||
hdmaTableAdr[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
hdmaRepCount[i]--;
|
||||
hdmaDoTransfer[i] = (hdmaRepCount[i] & 0x80) > 0;
|
||||
if((hdmaRepCount[i] & 0x7f) == 0) {
|
||||
hdmaRepCount[i] = mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i]++, TRUE
|
||||
);
|
||||
if(hdmaInd[i]) {
|
||||
dmaSize[i] = mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i]++, TRUE
|
||||
);
|
||||
dmaSize[i] |= mem_read(
|
||||
(dmaAadrBank[i] << 16) | hdmaTableAdr[i]++, TRUE
|
||||
) << 8;
|
||||
hdmaTimer += 16;
|
||||
}
|
||||
if(hdmaRepCount[i] == 0) {
|
||||
hdmaTerminated[i] = TRUE;
|
||||
}
|
||||
hdmaDoTransfer[i] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 doAutoJoyRead() {
|
||||
I64 i, bit;
|
||||
joypad1AutoRead = 0;
|
||||
joypad2AutoRead = 0;
|
||||
joypad1Val = joypad1State;
|
||||
joypad2Val = joypad2State;
|
||||
for(i = 0; i < 16; i++) {
|
||||
bit = joypad1Val & 0x1;
|
||||
joypad1Val >>= 1;
|
||||
joypad1Val |= 0x8000;
|
||||
joypad1AutoRead |= (bit << (15 - i));
|
||||
bit = joypad2Val & 0x1;
|
||||
joypad2Val >>= 1;
|
||||
joypad2Val |= 0x8000;
|
||||
joypad2AutoRead |= (bit << (15 - i));
|
||||
}
|
||||
}
|
||||
|
||||
U0 cpuCycle() {
|
||||
if(cpuCyclesLeft == 0) {
|
||||
cyclesLeft = 0;
|
||||
cpuMemOps = 0;
|
||||
cpu_cycle;
|
||||
cpuCyclesLeft += (cyclesLeft + 1 - cpuMemOps) * 6;
|
||||
}
|
||||
cpuCyclesLeft -= 2;
|
||||
}
|
||||
|
||||
|
||||
U0 cycle(Bool noPpu)
|
||||
{
|
||||
apuCatchCycles += (apuCyclesPerMaster * 2);
|
||||
|
||||
if(joypadStrobe) {
|
||||
joypad1Val = joypad1State;
|
||||
joypad2Val = joypad2State;
|
||||
}
|
||||
|
||||
if(hdmaTimer > 0) {
|
||||
hdmaTimer -= 2;
|
||||
} else if(dmaBusy) {
|
||||
handleDma;
|
||||
} else if (xPos < 536 || xPos >= 576) {
|
||||
// the cpu is paused for 40 cycles starting around dot 536
|
||||
cpuCycle;
|
||||
}
|
||||
|
||||
if(yPos == vTimer && vIrqEnabled) {
|
||||
if(!hIrqEnabled) {
|
||||
// only v irq enabed
|
||||
if(xPos == 0) {
|
||||
inIrq = TRUE;
|
||||
irqWanted = TRUE;
|
||||
}
|
||||
} else {
|
||||
// v and h irq enabled
|
||||
if(xPos == (hTimer * 4)) {
|
||||
inIrq = TRUE;
|
||||
irqWanted = TRUE;
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
xPos == (hTimer * 4)
|
||||
&& hIrqEnabled && !vIrqEnabled
|
||||
) {
|
||||
// only h irq enabled
|
||||
inIrq = TRUE;
|
||||
irqWanted = TRUE;
|
||||
}
|
||||
|
||||
if(xPos == 1024) {
|
||||
// start of hblank
|
||||
inHblank = TRUE;
|
||||
if(!inVblank) {
|
||||
handleHdma;
|
||||
}
|
||||
} else if(xPos == 0) {
|
||||
// end of hblank
|
||||
inHblank = FALSE;
|
||||
} else if(xPos == 512 && !noPpu) {
|
||||
// render line at cycle 512 for better support
|
||||
|
||||
renderLine(yPos);
|
||||
}
|
||||
|
||||
//renderLine(yPos);
|
||||
|
||||
if(yPos == cond(frameOverscan, 240, 225) && xPos == 0) {
|
||||
// start of vblank
|
||||
inNmi = TRUE;
|
||||
inVblank = TRUE;
|
||||
if(autoJoyRead) {
|
||||
autoJoyBusy = TRUE;
|
||||
autoJoyTimer = 4224;
|
||||
doAutoJoyRead;
|
||||
}
|
||||
if(nmiEnabled) {
|
||||
nmiWanted = TRUE;
|
||||
}
|
||||
} else if(yPos == 0 && xPos == 0) {
|
||||
// end of vblank
|
||||
inNmi = FALSE;
|
||||
inVblank = FALSE;
|
||||
initHdma;
|
||||
}
|
||||
|
||||
if(autoJoyBusy) {
|
||||
autoJoyTimer -= 2; // loop only runs every second master cycle
|
||||
if(autoJoyTimer == 0) {
|
||||
autoJoyBusy = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: in non-intelace mode, line 240 on every odd frame is 1360 cycles
|
||||
// and in interlace mode, every even frame is 263 lines
|
||||
xPos += 2;
|
||||
if(xPos == 1364) {
|
||||
xPos = 0;
|
||||
yPos++;
|
||||
if(yPos == 262) {
|
||||
// when finishing a frame, also catch up the apu
|
||||
catchUpApu;
|
||||
yPos = 0;
|
||||
frames++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define JPAD_Y 0
|
||||
#define JPAD_B 1
|
||||
#define JPAD_SELECT 2
|
||||
#define JPAD_START 3
|
||||
#define JPAD_UP 4
|
||||
#define JPAD_DOWN 5
|
||||
#define JPAD_LEFT 6
|
||||
#define JPAD_RIGHT 7
|
||||
#define JPAD_A 8
|
||||
#define JPAD_X 9
|
||||
#define JPAD_L 10
|
||||
#define JPAD_R 11
|
||||
|
||||
U0 setPad1Button(I64 num, I64 sc)
|
||||
{
|
||||
switch (KeyDown(sc))
|
||||
{
|
||||
case 0:
|
||||
joypad1State &= (~(1 << num)) & 0xfff;
|
||||
break;
|
||||
case 1:
|
||||
joypad1State |= (1 << num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Joypad1Update()
|
||||
{
|
||||
setPad1Button(JPAD_Y, Char2ScanCode('z'));
|
||||
setPad1Button(JPAD_B, Char2ScanCode('a'));
|
||||
setPad1Button(JPAD_X, Char2ScanCode('s'));
|
||||
setPad1Button(JPAD_A, Char2ScanCode('x'));
|
||||
setPad1Button(JPAD_L, Char2ScanCode('d'));
|
||||
setPad1Button(JPAD_R, Char2ScanCode('c'));
|
||||
setPad1Button(JPAD_SELECT, SC_SHIFT);
|
||||
setPad1Button(JPAD_START, SC_ENTER);
|
||||
setPad1Button(JPAD_UP, SC_CURSOR_UP);
|
||||
setPad1Button(JPAD_DOWN, SC_CURSOR_DOWN);
|
||||
setPad1Button(JPAD_LEFT, SC_CURSOR_LEFT);
|
||||
setPad1Button(JPAD_RIGHT, SC_CURSOR_RIGHT);
|
||||
}
|
||||
Reference in New Issue
Block a user