mirror of
https://git.checksum.fail/alec/templenes.git
synced 2026-05-26 17:22:55 +00:00
Add mapper support: MMC1, UNROM, CNROM, MMC3, Color Dreams, FFE Copier, Jaleco SS88006; Sound support, Initial GUI menu stuff
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
uncrustify.cfg
|
||||
.vscode/
|
||||
@@ -0,0 +1,76 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
I64 start_buf_num;
|
||||
U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
|
||||
|
||||
U0 AudioFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num)
|
||||
{
|
||||
I64 j=0,k;
|
||||
I64 intL, intR;
|
||||
U8 *buf2;
|
||||
|
||||
if (paused)
|
||||
{
|
||||
while (j<SND_BUF_LEN)
|
||||
{
|
||||
buf[j++]=0;
|
||||
buf[j++]=0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (j<SND_BUF_LEN)
|
||||
{
|
||||
// TODO: fix this - dirty hack to keep audio in sync
|
||||
if (FifoI64Cnt(audio_fifo_L)>8192)
|
||||
{
|
||||
while (FifoI64Cnt(audio_fifo_L)>7680)
|
||||
{
|
||||
FifoI64Rem(audio_fifo_L, &k);
|
||||
FifoI64Rem(audio_fifo_R, &k);
|
||||
}
|
||||
}
|
||||
|
||||
if (FifoI64Cnt(audio_fifo_L))
|
||||
{
|
||||
FifoI64Rem(audio_fifo_L, &intL);
|
||||
}
|
||||
else
|
||||
{
|
||||
intL = 0;
|
||||
}
|
||||
intL *= 0xFFFF;
|
||||
if (intL < 0)
|
||||
{
|
||||
intL += 0x1000000;
|
||||
}
|
||||
|
||||
if (FifoI64Cnt(audio_fifo_R))
|
||||
{
|
||||
FifoI64Rem(audio_fifo_R, &intR);
|
||||
}
|
||||
else
|
||||
{
|
||||
intR = 0;
|
||||
}
|
||||
intR *= 0xFFFF;
|
||||
if (intR < 0)
|
||||
{
|
||||
intR += 0x1000000;
|
||||
}
|
||||
|
||||
buf2 = buf+j;
|
||||
buf2[0] = 0;
|
||||
buf2[1] = intL;
|
||||
buf2[2] = intL >> 8;
|
||||
buf2[3] = intL >> 16;
|
||||
j++;
|
||||
|
||||
buf2 = buf+j;
|
||||
buf2[0] = 0;
|
||||
buf2[1] = intR;
|
||||
buf2[2] = intR >> 8;
|
||||
buf2[3] = intR >> 16;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,8 @@ U0 saveaccum(I64 n) {
|
||||
//helper variables
|
||||
U32 instructions = 0; //keep track of total instructions executed
|
||||
I32 clockticks6502 = 0, clockgoal6502 = 0;
|
||||
U16 oldpc, ea, reladdr, value, result;
|
||||
U8 opcode, oldcpustatus, useaccum;
|
||||
U16 oldpc=0, ea=0, reladdr=0, value=0, result=0;
|
||||
U8 opcode=0, oldcpustatus=0, useaccum=0;
|
||||
|
||||
//flag modifier functions (converted from macros)
|
||||
U0 setcarry() {
|
||||
@@ -105,17 +105,27 @@ U8 pull8() {
|
||||
|
||||
U0 reset6502() {
|
||||
pc = readRAM(0xFFFC) (U16) | (readRAM(0xFFFD) (U16) << 8);
|
||||
|
||||
instructions = 0;
|
||||
clockgoal6502 = 0;
|
||||
clockticks6502 = 0;
|
||||
|
||||
a = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
sp = 0xFD;
|
||||
//cpustatus |= FLAG_CONSTANT;
|
||||
cpustatus = FLAG_CONSTANT;
|
||||
cpustatus |= FLAG_CONSTANT;
|
||||
/*
|
||||
writeRAM(0x4017, 00);
|
||||
writeRAM(0x4015, 00);
|
||||
I64 m=0;
|
||||
for (m=0x4000;m<0x4010;m++)
|
||||
{
|
||||
writeRAM(m, 0);
|
||||
}
|
||||
for (m=0;m<0x800;m++)
|
||||
{
|
||||
writeRAM(m, 0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//addressing mode functions, calculates effective addresses
|
||||
@@ -658,6 +668,7 @@ U0 tya() {
|
||||
}
|
||||
|
||||
//undocumented instructions
|
||||
#define UNDOCUMENTED
|
||||
#ifdef UNDOCUMENTED
|
||||
U0 lax() {
|
||||
lda;
|
||||
@@ -715,7 +726,6 @@ U0 nmi6502() {
|
||||
push16(pc);
|
||||
push8(cpustatus);
|
||||
cpustatus |= FLAG_INTERRUPT;
|
||||
//cpustatus &= FLAG_INTERRUPT;
|
||||
pc = readRAM(0xFFFA) (U16) | (readRAM(0xFFFB) (U16) << 8);
|
||||
}
|
||||
|
||||
@@ -1378,5 +1388,4 @@ U16 getpc() {
|
||||
|
||||
U8 getop() {
|
||||
return(opcode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
#ifndef GUI_FONT
|
||||
#define GUI_FONT
|
||||
|
||||
U8 *gui_font_str = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_~./<>[]:& #=`|*?%+,()@a!b;c^{}";
|
||||
|
||||
asm {
|
||||
GUI_FONT_TBL::
|
||||
DU8 0b0, 0b0, 0b0, 0b0, 0b0;
|
||||
DU8 0b01110000, 0b10011000, 0b10101000, 0b11001000, 0b01110000;
|
||||
DU8 0b00100000, 0b01100000, 0b00100000, 0b00100000, 0b01110000;
|
||||
DU8 0b01110000, 0b10001000, 0b00110000, 0b01000000, 0b11111000;
|
||||
DU8 0b01110000, 0b10001000, 0b00110000, 0b10001000, 0b01110000;
|
||||
DU8 0b01010000, 0b10010000, 0b11111000, 0b00010000, 0b00010000;
|
||||
DU8 0b11111000, 0b10000000, 0b11110000, 0b00001000, 0b11110000;
|
||||
DU8 0b01110000, 0b10000000, 0b11110000, 0b10001000, 0b01110000;
|
||||
DU8 0b11111000, 0b00001000, 0b00010000, 0b00010000, 0b00010000;
|
||||
DU8 0b01110000, 0b10001000, 0b01110000, 0b10001000, 0b01110000;
|
||||
DU8 0b01110000, 0b10001000, 0b01111000, 0b00001000, 0b01110000;
|
||||
DU8 0b01110000, 0b10001000, 0b11111000, 0b10001000, 0b10001000;
|
||||
DU8 0b11110000, 0b10001000, 0b11110000, 0b10001000, 0b11110000;
|
||||
DU8 0b01110000, 0b10001000, 0b10000000, 0b10001000, 0b01110000;
|
||||
DU8 0b11110000, 0b10001000, 0b10001000, 0b10001000, 0b11110000;
|
||||
DU8 0b11111000, 0b10000000, 0b11110000, 0b10000000, 0b11111000;
|
||||
DU8 0b11111000, 0b10000000, 0b11110000, 0b10000000, 0b10000000;
|
||||
DU8 0b01111000, 0b10000000, 0b10011000, 0b10001000, 0b01110000;
|
||||
DU8 0b10001000, 0b10001000, 0b11111000, 0b10001000, 0b10001000;
|
||||
DU8 0b11111000, 0b00100000, 0b00100000, 0b00100000, 0b11111000;
|
||||
DU8 0b01111000, 0b00010000, 0b00010000, 0b10010000, 0b01100000;
|
||||
DU8 0b10010000, 0b10100000, 0b11100000, 0b10010000, 0b10001000;
|
||||
DU8 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b11111000;
|
||||
DU8 0b11011000, 0b10101000, 0b10101000, 0b10101000, 0b10001000;
|
||||
DU8 0b11001000, 0b10101000, 0b10101000, 0b10101000, 0b10011000;
|
||||
DU8 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b01110000;
|
||||
DU8 0b11110000, 0b10001000, 0b11110000, 0b10000000, 0b10000000;
|
||||
DU8 0b01110000, 0b10001000, 0b10101000, 0b10010000, 0b01101000;
|
||||
DU8 0b11110000, 0b10001000, 0b11110000, 0b10010000, 0b10001000;
|
||||
DU8 0b01111000, 0b10000000, 0b01110000, 0b00001000, 0b11110000;
|
||||
DU8 0b11111000, 0b00100000, 0b00100000, 0b00100000, 0b00100000;
|
||||
DU8 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01110000;
|
||||
DU8 0b10001000, 0b10001000, 0b01010000, 0b01010000, 0b00100000;
|
||||
DU8 0b10001000, 0b10101000, 0b10101000, 0b10101000, 0b01010000;
|
||||
DU8 0b10001000, 0b01010000, 0b00100000, 0b01010000, 0b10001000;
|
||||
DU8 0b10001000, 0b01010000, 0b00100000, 0b00100000, 0b00100000;
|
||||
DU8 0b11111000, 0b00010000, 0b00100000, 0b01000000, 0b11111000;
|
||||
DU8 0b00000000, 0b00000000, 0b11111000, 0b00000000, 0b00000000;
|
||||
DU8 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11111000;
|
||||
DU8 0b01101000, 0b10010000, 0b00000000, 0b00000000, 0b00000000;
|
||||
DU8 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00100000;
|
||||
DU8 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000;
|
||||
DU8 0b00010000, 0b00100000, 0b01000000, 0b00100000, 0b00010000;
|
||||
DU8 0b01000000, 0b00100000, 0b00010000, 0b00100000, 0b01000000;
|
||||
DU8 0b01110000, 0b01000000, 0b01000000, 0b01000000, 0b01110000;
|
||||
DU8 0b01110000, 0b00010000, 0b00010000, 0b00010000, 0b01110000;
|
||||
DU8 0b00000000, 0b00100000, 0b00000000, 0b00100000, 0b00000000;
|
||||
DU8 0b01100000, 0b10011000, 0b01110000, 0b10011000, 0b01101000;
|
||||
DU8 0b00100000, 0b00100000, 0b10101000, 0b01110000, 0b00100000;
|
||||
DU8 0b01010000, 0b11111000, 0b01010000, 0b11111000, 0b01010000;
|
||||
DU8 0b00000000, 0b11111000, 0b00000000, 0b11111000, 0b00000000;
|
||||
DU8 0b01001000, 0b10010000, 0b00000000, 0b00000000, 0b00000000;
|
||||
DU8 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000;
|
||||
DU8 0b10101000, 0b01110000, 0b11111000, 0b01110000, 0b10101000;
|
||||
DU8 0b01110000, 0b10001000, 0b00110000, 0b00000000, 0b00100000;
|
||||
DU8 0b10001000, 0b00010000, 0b00100000, 0b01000000, 0b10001000;
|
||||
DU8 0b00100000, 0b00100000, 0b11111000, 0b00100000, 0b00100000;
|
||||
DU8 0b00000000, 0b00000000, 0b00000000, 0b00100000, 0b01000000;
|
||||
DU8 0b00110000, 0b01000000, 0b01000000, 0b01000000, 0b00110000;
|
||||
DU8 0b01100000, 0b00010000, 0b00010000, 0b00010000, 0b01100000;
|
||||
DU8 0b01110000, 0b10011000, 0b10111000, 0b10000000, 0b01110000;
|
||||
DU8 0b00100000, 0b01000000, 0b00000000, 0b00000000, 0b00000000;
|
||||
DU8 0b00100000, 0b00100000, 0b00100000, 0b00000000, 0b00100000;
|
||||
DU8 0b01111000, 0b10100000, 0b01110000, 0b00101000, 0b11110000;
|
||||
DU8 0b00000000, 0b00100000, 0b00000000, 0b00100000, 0b01000000;
|
||||
DU8 0b01000000, 0b00100000, 0b00000000, 0b00000000, 0b00000000;
|
||||
DU8 0b00100000, 0b01010000, 0b00000000, 0b00000000, 0b00000000;
|
||||
DU8 0b00110000, 0b01000000, 0b11000000, 0b01000000, 0b00110000;
|
||||
DU8 0b01100000, 0b00010000, 0b00011000, 0b00010000, 0b01100000;
|
||||
DU8 0b00100000, 0b00100000, 0b01110000, 0b01110000, 0b11111000;
|
||||
DU8 0b11111000, 0b01110000, 0b01110000, 0b00100000, 0b00100000;
|
||||
DU8 0b00001000, 0b00111000, 0b11111000, 0b00111000, 0b00001000;
|
||||
DU8 0b10000000, 0b11100000, 0b11111000, 0b11100000, 0b10000000;
|
||||
DU8 0b00100000, 0b01100000, 0b11111000, 0b01100000, 0b00100000;
|
||||
DU8 0b00111000, 0b00100000, 0b00110000, 0b00001000, 0b10110000;
|
||||
DU8 0b11111100, 0b10000100, 0b11111100, 0b00000000, 0b00000000;
|
||||
DU8 0b00000000, 0b11111100, 0b00000000, 0b00000000, 0b00000000;
|
||||
DU8 0b11111000, 0b10001000, 0b10001000, 0b10001000, 0b11111000;
|
||||
DU8 0b00000000, 0b00000000, 0b00100000, 0b01010000, 0b00100000;
|
||||
DU8 0b01110000, 0b01000000, 0b01000000, 0b01000000, 0b00000000;
|
||||
DU8 0b00000000, 0b00010000, 0b00010000, 0b00010000, 0b01110000;
|
||||
DU8 0b00000000, 0b00000000, 0b00000000, 0b01000000, 0b00100000;
|
||||
DU8 0b00000000, 0b00100000, 0b01110000, 0b00100000, 0b00000000;
|
||||
DU8 0b11111000, 0b00001000, 0b11110000, 0b00100000, 0b11000000;
|
||||
DU8 0b00000000, 0b11111000, 0b01010000, 0b01100000, 0b01000000;
|
||||
DU8 0b00000000, 0b00010000, 0b00100000, 0b11100000, 0b00100000;
|
||||
DU8 0b00000000, 0b00100000, 0b11111000, 0b10001000, 0b00110000;
|
||||
DU8 0b00000000, 0b00000000, 0b11111000, 0b00100000, 0b11111000;
|
||||
DU8 0b00000000, 0b00010000, 0b11111000, 0b00110000, 0b11010000;
|
||||
DU8 0b00000000, 0b01000000, 0b11111000, 0b01010000, 0b01000000;
|
||||
DU8 0b00000000, 0b00000000, 0b11110000, 0b00010000, 0b11111000;
|
||||
DU8 0b00000000, 0b11111000, 0b00001000, 0b01111000, 0b11111000;
|
||||
DU8 0b00000000, 0b10101000, 0b10101000, 0b00010000, 0b01100000;
|
||||
DU8 0b00000000, 0b10000000, 0b01111000, 0b00000000, 0b00000000;
|
||||
DU8 0b11111000, 0b00101000, 0b00110000, 0b00100000, 0b11000000;
|
||||
DU8 0b00001000, 0b00110000, 0b11100000, 0b00100000, 0b00100000;
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,23 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
extern U0 initCart(U8 *rom_filename);
|
||||
|
||||
#define GUI_IDLE_TIMEOUT 30
|
||||
|
||||
class GUIModal
|
||||
{
|
||||
U8 *title;
|
||||
I64 x,y;
|
||||
I64 w,h;
|
||||
};
|
||||
|
||||
GUIModal *modal_about=CAlloc(sizeof(GUIModal));
|
||||
modal_about->title = "ABOUT";
|
||||
modal_about->x = 40;
|
||||
modal_about->y = 40;
|
||||
modal_about->w = 120;
|
||||
modal_about->h = 60;
|
||||
|
||||
U32 frame_count = 0;
|
||||
|
||||
CDC *ms_pointer = GRRead("Pointer.GR");
|
||||
@@ -9,6 +25,7 @@ DCColorChg(ms_pointer, LTPURPLE, 255);
|
||||
|
||||
Bool gui_focus = FALSE;
|
||||
|
||||
GUIModal *modal_focus = NULL;
|
||||
I64 menu_focus = -1;
|
||||
I64 item_clicked = -1;
|
||||
I64 mouse_old_x, mouse_old_y;
|
||||
@@ -16,44 +33,91 @@ I64 mouse_new_x, mouse_new_y;
|
||||
I64 idle_ctr = 0;
|
||||
|
||||
U8 **menu_bar=CAlloc(sizeof(U64)*6);
|
||||
menu_bar[0] = "Game";
|
||||
menu_bar[1] = "Config";
|
||||
menu_bar[2] = "Cheats";
|
||||
menu_bar[3] = "Misc";
|
||||
menu_bar[4] = "Help";
|
||||
menu_bar[0] = "GAME";
|
||||
menu_bar[1] = "CONFIG";
|
||||
menu_bar[2] = "CHEATS";
|
||||
menu_bar[3] = "MISC";
|
||||
menu_bar[4] = "HELP";
|
||||
|
||||
U8 **menu_items=NULL;
|
||||
|
||||
U8 **menu_game=CAlloc(sizeof(U64)*10);
|
||||
menu_game[0] = "Load ROM";
|
||||
menu_game[1] = "Reset";
|
||||
menu_game[0] = "LOAD ROM";
|
||||
menu_game[1] = "RESET";
|
||||
menu_game[2] = "";
|
||||
menu_game[3] = "Load State";
|
||||
menu_game[4] = "Save State";
|
||||
menu_game[3] = "LOAD STATE";
|
||||
menu_game[4] = "SAVE STATE";
|
||||
menu_game[5] = "";
|
||||
menu_game[6] = "Exit";
|
||||
menu_game[6] = "EXIT";
|
||||
|
||||
U8 **menu_config=CAlloc(sizeof(U64)*10);
|
||||
menu_config[0] = "Joypad 1";
|
||||
menu_config[1] = "Joypad 2";
|
||||
menu_config[0] = "JOYPAD 1";
|
||||
menu_config[1] = "JOYPAD 2";
|
||||
|
||||
U8 **menu_cheats=CAlloc(sizeof(U64)*10);
|
||||
menu_cheats[0] = "Add";
|
||||
menu_cheats[1] = "View/Edit";
|
||||
menu_cheats[2] = "Toggle";
|
||||
menu_cheats[0] = "ADD";
|
||||
menu_cheats[1] = "VIEW/EDIT";
|
||||
menu_cheats[2] = "TOGGLE";
|
||||
|
||||
U8 **menu_misc=CAlloc(sizeof(U64)*10);
|
||||
menu_misc[0] = "Scale2Fit";
|
||||
menu_misc[0] = "SCALE2FIT";
|
||||
|
||||
U8 **menu_help=CAlloc(sizeof(U64)*10);
|
||||
menu_help[0] = "About";
|
||||
menu_help[0] = "ABOUT";
|
||||
|
||||
U0 GrPrintShadow(CDC *dc, I64 x, I64 y, I64 c1=15, I64 c2=0, U8 *str)
|
||||
I64 GUIFontChr(I64 ch)
|
||||
{
|
||||
I64 i=0;
|
||||
while (gui_font_str[i])
|
||||
{
|
||||
if (gui_font_str[i]==ch)
|
||||
{
|
||||
return 5*i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
U0 GUIPrint(CDC *dc, I64 x, I64 y, U8 *str)
|
||||
{
|
||||
I64 i,j,k=0;
|
||||
U8 *font_ptr;
|
||||
while (str[k])
|
||||
{
|
||||
font_ptr = GUI_FONT_TBL + GUIFontChr(str[k]);
|
||||
for (j=0; j<5; j++)
|
||||
{
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if (font_ptr[j] & 1 << i)
|
||||
{
|
||||
GrPlot(dc, x+(7-i), y+j);
|
||||
}
|
||||
}
|
||||
}
|
||||
k++;
|
||||
x+=8;
|
||||
}
|
||||
}
|
||||
|
||||
U0 GUIPrintShadow(CDC *dc, I64 x, I64 y, I64 c1=15, I64 c2=0, U8 *str)
|
||||
{
|
||||
dc->color=c2;
|
||||
GrPrint(dc, x+1, y+1, str);
|
||||
GUIPrint(dc, x+1, y+1, str);
|
||||
dc->color=c1;
|
||||
GrPrint(dc, x, y, str);
|
||||
GUIPrint(dc, x, y, str);
|
||||
}
|
||||
|
||||
U0 GUIDrawModal()
|
||||
{
|
||||
GUIModal *m=modal_focus;
|
||||
if (m)
|
||||
{
|
||||
//testing
|
||||
TG_Canvas->color=12;
|
||||
GrRect(TG_Canvas,m->x,m->y,m->w,m->h);
|
||||
}
|
||||
}
|
||||
|
||||
U0 GUIDrawMenuHeader()
|
||||
@@ -68,18 +132,18 @@ U0 GUIDrawMenuHeader()
|
||||
{
|
||||
if (i+1==menu_focus)
|
||||
{
|
||||
GrPrintShadow(TG_Canvas, (64*i) - 64, 2, YELLOW, 0, menu_bar[i++]);
|
||||
GUIPrintShadow(TG_Canvas, (64*i) - 64, 2, YELLOW, 0, menu_bar[i++]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mouse_new_x > (64*i+1) && mouse_new_x < (64*i+1)+64 &&
|
||||
mouse_new_y > -1 && mouse_new_y < 12)
|
||||
{
|
||||
GrPrintShadow(TG_Canvas, (64*i) - 64, 2, CYAN, 0, menu_bar[i++]);
|
||||
GUIPrintShadow(TG_Canvas, (64*i) - 64, 2, CYAN, 0, menu_bar[i++]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GrPrintShadow(TG_Canvas, (64*i) - 64, 2, 15, 0, menu_bar[i++]);
|
||||
GUIPrintShadow(TG_Canvas, (64*i) - 64, 2, 15, 0, menu_bar[i++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,11 +200,11 @@ U0 GUIDrawMenuFocused()
|
||||
if (mouse_new_x > (64*menu_focus)-64 && mouse_new_x < (64*menu_focus) + 32 &&
|
||||
mouse_new_y > 4+((i+1)*10) && mouse_new_y < 4+((i+1)*10)+10)
|
||||
{
|
||||
GrPrintShadow(TG_Canvas, (64*menu_focus)-62, 4+(i*10), CYAN, 0, menu_items[i++]);
|
||||
GUIPrintShadow(TG_Canvas, (64*menu_focus)-62, 4+(i*10), CYAN, 0, menu_items[i++]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GrPrintShadow(TG_Canvas, (64*menu_focus)-62, 4+(i*10), 15, 0, menu_items[i++]);
|
||||
GUIPrintShadow(TG_Canvas, (64*menu_focus)-62, 4+(i*10), 15, 0, menu_items[i++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,17 +265,23 @@ U0 UpdateGUI()
|
||||
case 0:
|
||||
switch (menu_focus)
|
||||
{
|
||||
case 1:
|
||||
modal_focus = NULL;
|
||||
break;
|
||||
case 4:
|
||||
fit_screen = !fit_screen;
|
||||
if (fit_screen)
|
||||
{
|
||||
menu_misc[0] = "Scale2Fit +";
|
||||
menu_misc[0] = "SCALE2FIT +";
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_misc[0] = "Scale2Fit";
|
||||
menu_misc[0] = "SCALE2FIT";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
modal_focus = modal_about;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -245,12 +315,12 @@ U0 UpdateGUI()
|
||||
}
|
||||
}
|
||||
|
||||
if (menu_focus<1)
|
||||
if (menu_focus<1 && !modal_focus)
|
||||
{
|
||||
gui_focus = FALSE;
|
||||
}
|
||||
|
||||
if (menu_focus>0)
|
||||
if (menu_focus>0 || modal_focus)
|
||||
{
|
||||
paused = TRUE;
|
||||
}
|
||||
@@ -274,6 +344,10 @@ U0 UpdateGUI()
|
||||
|
||||
if (!idle_ctr || (frame_count < idle_ctr + GUI_IDLE_TIMEOUT) || gui_focus)
|
||||
{ //Draw mouse pointer
|
||||
if (modal_focus)
|
||||
{
|
||||
GUIDrawModal;
|
||||
}
|
||||
GUIDrawMenuHeader;
|
||||
GUIDrawMenuFocused;
|
||||
GUIDrawPointer;
|
||||
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
#define GP_TX_PORT 0x0378
|
||||
#define GP_RX_PORT 0x0379
|
||||
|
||||
#define GP_SNES_DELAY 0
|
||||
|
||||
#define GP_SNES_POWER 0xFC
|
||||
#define GP_SNES_CLOCK 0x01
|
||||
#define GP_SNES_LATCH 0x02
|
||||
|
||||
U8 gp_data[16];
|
||||
MemSet(&gp_data, 16, 0);
|
||||
I64 gp_ctr;
|
||||
|
||||
U0 updateGamepad()
|
||||
{
|
||||
return;
|
||||
OutU8(GP_TX_PORT,GP_SNES_POWER|GP_SNES_CLOCK|GP_SNES_LATCH);
|
||||
Sleep(GP_SNES_DELAY*2);
|
||||
OutU8(GP_TX_PORT,GP_SNES_POWER|GP_SNES_CLOCK);
|
||||
gp_ctr=0;
|
||||
while (gp_ctr<12)
|
||||
{
|
||||
Sleep(GP_SNES_DELAY);
|
||||
OutU8(GP_TX_PORT,GP_SNES_POWER);
|
||||
gp_data[gp_ctr]=InU8(GP_RX_PORT)^0x7F;
|
||||
Sleep(GP_SNES_DELAY);
|
||||
OutU8(GP_TX_PORT,GP_SNES_POWER|GP_SNES_CLOCK);
|
||||
gp_ctr++;
|
||||
}
|
||||
}
|
||||
+972
@@ -0,0 +1,972 @@
|
||||
U8 *Mem2MegAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL)
|
||||
{/*Alloc 2Meg pages from BlkPool. Don't link to task.
|
||||
(Linking to a task means they will be freed when the task dies.)
|
||||
It might give you more than you asked for
|
||||
so a ptr to a page count is passed.
|
||||
|
||||
Return: NULL if out of memory.
|
||||
*/
|
||||
I64 i,j,*pte,num=*_pages2Meg;
|
||||
CMemBlk *res=NULL,*m,*m1;
|
||||
|
||||
if (!bp) bp=sys_code_bp;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&bp->locked_flags,BPlf_LOCKED))
|
||||
PAUSE
|
||||
num<<=21-MEM_PAG_BITS;
|
||||
|
||||
m=&bp->mem_free_2meg_lst;
|
||||
while (TRUE) {
|
||||
if (!(res=m->next))
|
||||
break;
|
||||
if (res->pags<num)
|
||||
m=res;
|
||||
else {
|
||||
if (res->pags==num) {
|
||||
m->next=res->next;
|
||||
goto am_done;
|
||||
} else {
|
||||
res->pags-=num;
|
||||
res(U8 *)+=res->pags<<MEM_PAG_BITS;
|
||||
res->pags=num;
|
||||
goto am_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m=&bp->mem_free_lst;
|
||||
while (TRUE) {
|
||||
if (!(res=m->next)) {
|
||||
num=0;
|
||||
res=NULL; //Out of memory
|
||||
goto am_done;
|
||||
}
|
||||
if (res->pags<num)
|
||||
m=res;
|
||||
else {
|
||||
if (res->pags==num) {
|
||||
if (res(U8 *)&0x1FFFFF)
|
||||
m=res;
|
||||
else {
|
||||
m->next=res->next;
|
||||
goto am_done;
|
||||
}
|
||||
} else {
|
||||
if (i=(res(U8 *)&0x1FFFFF)>>MEM_PAG_BITS) {
|
||||
j=1<<(21-MEM_PAG_BITS)-i;
|
||||
if (res->pags<num+j)
|
||||
m=res;
|
||||
else if (res->pags==num+j) {
|
||||
res->pags-=num;
|
||||
res(U8 *)+=res->pags<<MEM_PAG_BITS;
|
||||
res->pags=num;
|
||||
goto am_done;
|
||||
} else {
|
||||
m1=res;
|
||||
res(U8 *)+=j<<MEM_PAG_BITS;
|
||||
res->pags=num;
|
||||
m=res(U8 *)+num<<MEM_PAG_BITS;
|
||||
m->pags=m1->pags-num-j;
|
||||
m1->pags=j;
|
||||
m->next=m1->next;
|
||||
m1->next=m;
|
||||
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
|
||||
goto am_done;
|
||||
}
|
||||
} else {
|
||||
m=m->next=res(U8 *)+num<<MEM_PAG_BITS;
|
||||
m->next=res->next;
|
||||
m->pags=res->pags-num;
|
||||
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
|
||||
res->pags=num;
|
||||
goto am_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
am_done:
|
||||
i=num<<MEM_PAG_BITS;
|
||||
bp->used_u8s+=i;
|
||||
num>>=21-MEM_PAG_BITS;
|
||||
*_pages2Meg=num;
|
||||
m=res;
|
||||
m1=m(U8 *)+i;
|
||||
while (m<m1) {
|
||||
pte=MemPageTable(m);
|
||||
*pte &= ~0x18;
|
||||
InvlPg(m);
|
||||
m(U8 *)+=0x200000;
|
||||
}
|
||||
LBtr(&bp->locked_flags,BPlf_LOCKED);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *Mem2MegUncachedAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL)
|
||||
{/*Alloc 2Meg pages from BlkPool. Don't link to task.
|
||||
(Linking to a task means they will be freed when the task dies.)
|
||||
It will be marked uncached. It might give you more than you asked for
|
||||
so a ptr to a page count is passed.
|
||||
|
||||
Return: NULL if out of memory.
|
||||
*/
|
||||
CMemBlk *res,*m,*m1;
|
||||
I64 num=*_pages2Meg,*pte;
|
||||
if (res=Mem2MegAlloc(_pages2Meg,bp)) {
|
||||
num=*_pages2Meg;
|
||||
m=res;
|
||||
m1=m(U8 *)+num<<21;
|
||||
while (m<m1) {
|
||||
pte=MemPageTable(m);
|
||||
*pte= *pte& ~0x18 |0x10;
|
||||
InvlPg(m);
|
||||
m(U8 *)+=0x200000;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CHeapCtrl *HeapCtrlBPInit(CBlkPool *bp,I64 pags)
|
||||
{//Make mem chunk into HeapCtrl and BlkPool.
|
||||
I64 num;
|
||||
CMemBlk *m;
|
||||
CHeapCtrl *hc;
|
||||
MemSet(bp,0,sizeof(CBlkPool)+sizeof(CHeapCtrl));
|
||||
hc=HeapCtrlInit(bp(U8 *)+sizeof(CBlkPool),,bp);
|
||||
m=(bp(U8 *)+sizeof(CBlkPool)+sizeof(CHeapCtrl)+MEM_PAG_SIZE-1)&
|
||||
~(MEM_PAG_SIZE-1);
|
||||
num=(bp(U8 *)+pags<<MEM_PAG_BITS-m(U8 *))>>MEM_PAG_BITS;
|
||||
bp->alloced_u8s=(pags-num)<<MEM_PAG_BITS;
|
||||
BlkPoolAdd(bp,m,num);
|
||||
return hc;
|
||||
}
|
||||
|
||||
class CSndWaveCtrl
|
||||
{
|
||||
I64 sample_rate,sample_bits,channels;
|
||||
F64 freq_multiplier,amp_multiplier;
|
||||
F64 phase,last_y,last_dydt,next_y;
|
||||
};
|
||||
|
||||
#define WF_NULL 0
|
||||
#define WF_SQUARE 1
|
||||
#define WF_SINE 2
|
||||
#define WF_TRI 3
|
||||
#define WF_SAWTOOTH 4
|
||||
#define WF_NOISE 5
|
||||
#define WF_WAVEFORMS_NUM 6
|
||||
|
||||
//snd devs
|
||||
#define SD_PC_SPEAKER 0
|
||||
#define SD_HD_AUDIO 1
|
||||
|
||||
#define SND_SAMPLE_RATE 48000
|
||||
#define SND_SAMPLE_BITS 16
|
||||
#define SND_OCHANNELS 2
|
||||
#define SND_ICHANNELS 2
|
||||
#define SND_OUT_CONTAINER U32
|
||||
#define SND_IN_CONTAINER I16
|
||||
#define SND_BUF_LEN 0x400
|
||||
#define SND_BUF_TIME_mS (SND_BUF_LEN/SND_OCHANNELS*1000.0/\
|
||||
SND_SAMPLE_RATE)
|
||||
|
||||
F64 snd_freq=0;
|
||||
I64 snd_dev=SD_PC_SPEAKER;
|
||||
Bool snd_record=FALSE;
|
||||
F64 snd_vol=0.1;
|
||||
U0 (*fp_snd)(F64 freq,I64 waveform,F64 amp)=NULL;
|
||||
U0 (*fp_snd_record)(F64 freq,I64 waveform,F64 amp)=NULL;
|
||||
U0 (*fp_snd_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
|
||||
U0 (*fp_snd_copy_buf)(SND_IN_CONTAINER *buf,I64 buf_num)=NULL;
|
||||
|
||||
I64 snd_obuf_num,snd_ibuf_num;
|
||||
|
||||
#define Sf_FILLING_OUT 0
|
||||
I64 snd_flags;
|
||||
|
||||
#define HD_1_CHAN 0
|
||||
#define HD_2_CHAN 1
|
||||
#define HD_3_CHAN 2
|
||||
#define HD_4_CHAN 3
|
||||
|
||||
#define HD_8_BIT 0
|
||||
#define HD_16_BIT 1
|
||||
#define HD_20_BIT 2
|
||||
#define HD_24_BIT 3
|
||||
#define HD_32_BIT 4
|
||||
|
||||
#define HD_48kHz 0
|
||||
|
||||
#define HD_DFT_OUT_FMT (HD_2_CHAN+HD_16_BIT<<4+HD_48kHz<<8)
|
||||
#define HD_DFT_IN_FMT (HD_2_CHAN+HD_16_BIT<<4+HD_48kHz<<8)
|
||||
|
||||
#define HD_POS_BUF_MULTIPLES 0x1000
|
||||
|
||||
#define HD_CORB_ENTRIES 256
|
||||
#define HD_RIRB_ENTRIES 256
|
||||
#define HD_BDL_ENTRIES 256
|
||||
|
||||
#define HD_GCTL 0x08
|
||||
#define HD_STATESTS 0x0E
|
||||
#define HD_GSTS 0x10
|
||||
#define HD_CORBLBASE 0x40
|
||||
#define HD_CORBUBASE 0x44
|
||||
#define HD_CORBWP 0x48
|
||||
#define HD_CORBRP 0x4A
|
||||
#define HD_CORBCTL 0x4C
|
||||
#define HD_CORBST 0x4D
|
||||
#define HD_RIRBLBASE 0x50
|
||||
#define HD_RIRBUBASE 0x54
|
||||
#define HD_RIRBWP 0x58
|
||||
#define HD_RIRBCTL 0x5C
|
||||
#define HD_RIRBSTS 0x5D
|
||||
|
||||
#define STRCTL 0x00
|
||||
#define STRSTS 0x03
|
||||
#define STRLPIB 0x04
|
||||
#define STRCBL 0x08
|
||||
#define STRLVI 0x0C
|
||||
#define STRFIFOW 0x0E
|
||||
#define STRFIFOS 0x10
|
||||
#define STRFMT 0x12
|
||||
#define STRBDPL 0x18
|
||||
#define STRBDPU 0x1C
|
||||
|
||||
#define ISTR0 0x080
|
||||
#define ISTR1 0x0A0
|
||||
#define ISTR2 0x0C0
|
||||
#define ISTR3 0x0E0
|
||||
#define OSTR0 0x100
|
||||
#define OSTR1 0x120
|
||||
#define OSTR2 0x140
|
||||
#define OSTR3 0x160
|
||||
|
||||
#define VERB_GET_PARAM 0xF0000
|
||||
#define VERB_CONNECT_SEL_GET 0xF0100
|
||||
#define VERB_CONNECT_SEL_SET 0x70100
|
||||
#define VERB_GET_CONNECT_LST 0xF0200
|
||||
#define VERB_PROCESS_STATE_GET 0xF0300
|
||||
#define VERB_PROCESS_STATE_SET 0x70300
|
||||
#define VERB_COEFF_IDX_GET 0xD0000
|
||||
#define VERB_COEFF_IDX_SET 0x50000
|
||||
#define VERB_PROCESS_COEFF_GET 0xC0000
|
||||
#define VERB_PROCESS_COEFF_SET 0x40000
|
||||
#define VERB_AMPLIFIER_GAIN_GET 0xB0000
|
||||
#define VERB_AMPLIFIER_GAIN_SET 0x30000
|
||||
#define VERB_STREAM_FMT_GET 0xA0000
|
||||
#define VERB_STREAM_FMT_SET 0x20000
|
||||
#define VERB_DIGIT_CONVERT1_GET 0xF0D00
|
||||
#define VERB_DIGIT_CONVERT1_SET 0x70D00
|
||||
#define VERB_DIGIT_CONVERT2_GET 0xF0D00
|
||||
#define VERB_DIGIT_CONVERT2_SET 0x70E00
|
||||
#define VERB_POWER_STATE_GET 0xF0500
|
||||
#define VERB_POWER_STATE_SET 0x70500
|
||||
#define VERB_CHAN_STREAM_ID_GET 0xF0600
|
||||
#define VERB_CHAN_STREAM_ID_SET 0x70600
|
||||
#define VERB_SDI_SEL_GET 0xF0400
|
||||
#define VERB_SDI_SEL_SET 0x70400
|
||||
#define VERB_PIN_WIDGET_CTL_GET 0xF0700
|
||||
#define VERB_PIN_WIDGET_CTL_SET 0x70700
|
||||
#define VERB_UNSOL_ENABLE_GET 0xF0800
|
||||
#define VERB_UNSOL_ENABLE_SET 0x70800
|
||||
#define VERB_PIN_SENSE_GET 0xF0900
|
||||
#define VERB_PIN_SENSE_SET 0x70900
|
||||
#define VERB_EAPDBTL_ENABLE_GET 0xF0C00
|
||||
#define VERB_EAPDBTL_ENABLE_SET 0x70C00
|
||||
#define VERB_BEEP_CTL_GET 0xF0A00
|
||||
#define VERB_BEEP_CTL_SET 0x70A00
|
||||
#define VERB_GPI_CTRL0_GET 0xF1000
|
||||
#define VERB_GPI_CTRL0_SET 0x71000
|
||||
#define VERB_GPI_CTRL1_GET 0xF1100
|
||||
#define VERB_GPI_CTRL1_SET 0x71100
|
||||
#define VERB_GPI_CTRL2_GET 0xF1200
|
||||
#define VERB_GPI_CTRL2_SET 0x71200
|
||||
#define VERB_GPI_CTRL3_GET 0xF1300
|
||||
#define VERB_GPI_CTRL3_SET 0x71300
|
||||
#define VERB_GPI_CTRL4_GET 0xF1400
|
||||
#define VERB_GPI_CTRL4_SET 0x71400
|
||||
#define VERB_GPI_CTRL5_GET 0xF1500
|
||||
#define VERB_GPI_CTRL5_SET 0x71500
|
||||
#define VERB_GPI_CTRL6_GET 0xF1600
|
||||
#define VERB_GPI_CTRL6_SET 0x71600
|
||||
#define VERB_GPI_CTRL7_GET 0xF1700
|
||||
#define VERB_GPI_CTRL7_SET 0x71700
|
||||
#define VERB_GPI_CTRL8_GET 0xF1800
|
||||
#define VERB_GPI_CTRL8_SET 0x71800
|
||||
#define VERB_GPI_CTRL9_GET 0xF1900
|
||||
#define VERB_GPI_CTRL9_SET 0x71900
|
||||
#define VERB_GPI_CTRLA_GET 0xF1A00
|
||||
#define VERB_GPI_CTRLA_SET 0x71A00
|
||||
#define VERB_VOL_CTL_GET 0xF0F00
|
||||
#define VERB_VOL_CTL_SET 0x70F00
|
||||
#define VERB_SUB_SYS_ID0_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID0_SET 0x72000
|
||||
#define VERB_SUB_SYS_ID1_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID1_SET 0x72100
|
||||
#define VERB_SUB_SYS_ID2_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID2_SET 0x72200
|
||||
#define VERB_SUB_SYS_ID3_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID3_SET 0x72300
|
||||
#define VERB_CFG_DFT0_GET 0xF1C00
|
||||
#define VERB_CFG_DFT0_SET 0x71C00
|
||||
#define VERB_CFG_DFT1_GET 0xF1C00
|
||||
#define VERB_CFG_DFT1_SET 0x71D00
|
||||
#define VERB_CFG_DFT2_GET 0xF1C00
|
||||
#define VERB_CFG_DFT2_SET 0x71E00
|
||||
#define VERB_CFG_DFT3_GET 0xF1C00
|
||||
#define VERB_CFG_DFT3_SET 0x71F00
|
||||
#define VERB_STRIPE_CTL_GET 0xF2400
|
||||
#define VERB_STRIPE_CTL_SET 0x72400
|
||||
#define VERB_RST 0x7FF00
|
||||
|
||||
//Parameters
|
||||
#define P_VENDOR_ID 0x00
|
||||
#define P_REVISION_ID 0x02
|
||||
#define P_SUBNODE_CNT 0x04
|
||||
#define P_FUN_GRP_TYPE 0x05
|
||||
#define P_AUDIO_FUN_CAP 0x08
|
||||
#define P_AUDIO_WIDGET_CAP 0x09
|
||||
#define P_SAMPLE_SIZE_RATE_CAP 0x0A
|
||||
#define P_STREAM_FMTS 0x0B
|
||||
#define P_PIN_CAP 0x0C
|
||||
#define P_INPUT_AMP_CAP 0x0D
|
||||
#define P_OUTPUT_AMP_CAP 0x12
|
||||
#define P_CONNECT_LST_LEN 0x0E
|
||||
#define P_POWER_STATES 0x0F
|
||||
#define P_PROCESSING_CAP 0x10
|
||||
#define P_GPIO_CNT 0x11
|
||||
#define P_VOL_KNOB_CAP 0x13
|
||||
|
||||
//Function Group Types
|
||||
//00 reserved
|
||||
#define FGT_AUDIO 1
|
||||
#define FGT_VENDOR_MODEM 2
|
||||
//03-7F reserved
|
||||
//80-FF vendor function group
|
||||
|
||||
//Audio Widget Types
|
||||
#define AWT_OUTPUT 0x0
|
||||
#define AWT_INPUT 0x1
|
||||
#define AWT_MIXER 0x2
|
||||
#define AWT_SELECTOR 0x3
|
||||
#define AWT_PIN_COMPLEX 0x4
|
||||
#define AWT_POWER_WIDGET 0x5
|
||||
#define AWT_VOL_KNOB_WIDGET 0x6
|
||||
#define AWT_BEEP_GEN_WIDGET 0x7
|
||||
#define AWT_VENDOR 0xF
|
||||
#define AWT_NODE 0x10
|
||||
DefineLstLoad("ST_AUDIO_WIDGET_TYPES",
|
||||
"Output\0Input\0Mixer\0Sellector\0Pin Complex\0"
|
||||
"Power Widget\0Vol Knob\0Beep Gen\0\0\0\0\0\0\0\0Vendor\0Node\0");
|
||||
|
||||
class CHDBufDesc
|
||||
{
|
||||
I32 *buf;
|
||||
U32 len;
|
||||
U32 ctrl;
|
||||
};
|
||||
|
||||
#define HD_TONES 8
|
||||
|
||||
class CHDAudioCtrl
|
||||
{
|
||||
U8 *bar;
|
||||
CBlkPool *bp;
|
||||
CHeapCtrl *hc;
|
||||
I64 cad;
|
||||
U32 *corb;
|
||||
I64 *rirb;
|
||||
CHDBufDesc *ostr0_bdl,*istr0_bdl;
|
||||
SND_OUT_CONTAINER *ostr0_buf[2],*o_tmp_buf;
|
||||
SND_IN_CONTAINER *istr0_buf[2];
|
||||
CTask *task;
|
||||
I64 waveform;
|
||||
F64 freq,amp;
|
||||
CSndWaveCtrl *tone_swcs[HD_TONES];
|
||||
U8 rirb_rp,corb_wp;
|
||||
Bool audio_task_started,in_running,out_running;
|
||||
} hda;
|
||||
MemSet(&hda,0,sizeof(CHDAudioCtrl));
|
||||
|
||||
F64 SinPhaseCont(F64 last_y,F64 last_dydt,
|
||||
F64 current_amp,F64 phase_offset)
|
||||
{//Next sample of sin waveform.
|
||||
F64 phase;
|
||||
phase=last_y/current_amp;
|
||||
if (phase>1.0) phase=1.0;
|
||||
if (phase<-1.0) phase=-1.0;
|
||||
if (last_dydt<0)
|
||||
phase=pi-ASin(phase);
|
||||
else
|
||||
phase=ASin(phase);
|
||||
return phase-phase_offset;
|
||||
}
|
||||
|
||||
public CSndWaveCtrl *SndWaveCtrlNew(I64 sample_rate=8000,I64 sample_bits=24,
|
||||
I64 channels=2,CTask *mem_task=NULL)
|
||||
{//MAlloc ctrl struct for generating waveforms.
|
||||
CSndWaveCtrl *swc=CAlloc(sizeof(CSndWaveCtrl),mem_task);
|
||||
swc->freq_multiplier=1.0;
|
||||
swc->amp_multiplier=1.0;
|
||||
swc->sample_rate=sample_rate;
|
||||
swc->sample_bits=sample_bits;
|
||||
swc->channels=channels;
|
||||
swc->last_dydt=1.0;
|
||||
return swc;
|
||||
}
|
||||
|
||||
public U0 SndWaveCtrlDel(CSndWaveCtrl *swc)
|
||||
{//Free waveform ctrl.
|
||||
Free(swc);
|
||||
}
|
||||
|
||||
public U0 SndWaveAddBuf(CSndWaveCtrl *swc,U8 *buf,I64 num_samples,
|
||||
F64 _freq,I64 _waveform=WF_SQUARE,F64 _amp=1.0,F64 _left=1.0, F64 _right=1.0)
|
||||
{//Add waveform to buffer.
|
||||
//num_samples is multiplied by channels to get buf_len.
|
||||
//left,right range from 0.0-1.0
|
||||
//Supports 16,24 and 32 bits
|
||||
I64 reg i,reg j,reg k;
|
||||
F64 a,f,amp,reg phase;
|
||||
if (!swc) return;
|
||||
_freq*=swc->freq_multiplier;
|
||||
_amp*=swc->amp_multiplier;
|
||||
if (!_freq||!_amp) {
|
||||
swc->last_y=swc->phase=0;
|
||||
swc->last_dydt=1.0;
|
||||
} else {
|
||||
phase=swc->phase;
|
||||
i=0;
|
||||
amp=Min(I32_MAX,I32_MAX*_amp);
|
||||
f=2*pi/swc->sample_rate*_freq;
|
||||
switch (_waveform) {
|
||||
case WF_NOISE:
|
||||
a=2.0/pi*amp;
|
||||
break;
|
||||
case WF_SAWTOOTH:
|
||||
a=amp/pi;
|
||||
break;
|
||||
case WF_SINE:
|
||||
phase=SinPhaseCont(swc->last_y,swc->last_dydt,amp,0.0);
|
||||
break;
|
||||
}
|
||||
while (phase<0)
|
||||
phase+=2*pi;
|
||||
while (phase>=2*pi)
|
||||
phase-=2*pi;
|
||||
num_samples*=swc->channels;
|
||||
while (i<num_samples) {
|
||||
switch (_waveform) {
|
||||
case WF_SQUARE:
|
||||
if (phase>=pi)
|
||||
j=-amp;
|
||||
else
|
||||
j=amp;
|
||||
break;
|
||||
case WF_SINE:
|
||||
j=amp*Sin(phase);
|
||||
break;
|
||||
case WF_TRI:
|
||||
if (phase>=pi) {
|
||||
swc->last_y=swc->next_y;
|
||||
swc->next_y=-amp*Sign(swc->last_y)+.00001;
|
||||
phase-=pi;
|
||||
}
|
||||
j=(swc->last_y*(pi-phase)+swc->next_y*phase)/pi;
|
||||
break;
|
||||
case WF_SAWTOOTH:
|
||||
j=a*(phase-pi);
|
||||
break;
|
||||
case WF_NOISE:
|
||||
if (phase<pi) {
|
||||
if (phase<f) {
|
||||
swc->last_y=swc->next_y;
|
||||
swc->next_y=a*RandI16/U16_MAX;
|
||||
}
|
||||
j=swc->last_y*(pi-phase)+swc->next_y*phase;
|
||||
} else {
|
||||
if (phase-pi<f) {
|
||||
swc->last_y=swc->next_y;
|
||||
swc->next_y=a*RandI16/U16_MAX;
|
||||
}
|
||||
j=swc->last_y*(2.0*pi-phase)+swc->next_y*(phase-pi);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//left channel
|
||||
k=j*_left;
|
||||
if (swc->sample_bits==16) {
|
||||
k>>=16;
|
||||
buf(I16 *)[i++]+=k;
|
||||
} else {
|
||||
if (swc->sample_bits==24)
|
||||
k&=0xFFFFFF00;
|
||||
buf(I32 *)[i++]+=k;
|
||||
}
|
||||
//right channel
|
||||
if (swc->channels==2) {
|
||||
k=j*_right;
|
||||
if (swc->sample_bits==16) {
|
||||
k>>=16;
|
||||
buf(I16 *)[i++]+=k;
|
||||
} else {
|
||||
if (swc->sample_bits==24)
|
||||
k&=0xFFFFFF00;
|
||||
buf(I32 *)[i++]+=k;
|
||||
}
|
||||
}
|
||||
phase+=f;
|
||||
while (phase>=2*pi)
|
||||
phase-=2*pi;
|
||||
}
|
||||
if (_waveform==WF_SINE) {
|
||||
swc->last_y=amp*Sin(phase);
|
||||
swc->last_dydt=Cos(phase);
|
||||
}
|
||||
swc->phase=phase;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDSyncCORB()
|
||||
{
|
||||
U16 *wp,*rp;
|
||||
wp =hda.bar+HD_CORBWP;
|
||||
*wp=hda.corb_wp;
|
||||
rp =hda.bar+HD_CORBRP;
|
||||
while (*rp&255!=hda.corb_wp)
|
||||
Yield;
|
||||
}
|
||||
|
||||
U0 HDWriteCORB(I64 cad,I64 nid,U32 val)
|
||||
{
|
||||
val|=cad<<28+nid<<20;
|
||||
hda.corb[++hda.corb_wp]=val;
|
||||
}
|
||||
|
||||
I64 HDSyncRIRB()
|
||||
{
|
||||
U16 *_w;
|
||||
I64 wp,res=0;
|
||||
_w=hda.bar+HD_RIRBWP;
|
||||
wp=*_w;
|
||||
while (hda.rirb_rp!=wp)
|
||||
res=hda.rirb[++hda.rirb_rp];
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 HDReadRIRB()
|
||||
{
|
||||
U16 *_w;
|
||||
I64 wp,res=0;
|
||||
_w=hda.bar+HD_RIRBWP;
|
||||
do {
|
||||
Yield;
|
||||
wp=*_w;
|
||||
} while (wp==hda.rirb_rp);
|
||||
res=hda.rirb[++hda.rirb_rp];
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 HDWriteCORBSync(I64 cad,I64 nid,U32 val)
|
||||
{
|
||||
HDSyncCORB;
|
||||
HDSyncRIRB;
|
||||
HDWriteCORB(cad,nid,val);
|
||||
HDSyncCORB;
|
||||
return HDReadRIRB;
|
||||
}
|
||||
|
||||
Bool HDTestCORBSync(I64 cad,I64 nid,U32 val)
|
||||
{ //Checks for a response
|
||||
U16 *_w;
|
||||
I64 wp;
|
||||
|
||||
HDSyncCORB;
|
||||
HDSyncRIRB;
|
||||
HDWriteCORB(cad,nid,val);
|
||||
HDSyncCORB;
|
||||
|
||||
Sleep(1);
|
||||
_w=hda.bar+HD_RIRBWP;
|
||||
wp=*_w;
|
||||
if (wp==hda.rirb_rp)
|
||||
return FALSE;
|
||||
HDReadRIRB;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U0 HDTraverse(I64 cad,I64 nid)
|
||||
{
|
||||
I64 i,len,aud_cap,type;
|
||||
HDWriteCORBSync(cad,nid,VERB_POWER_STATE_SET+0x00); //0 is on
|
||||
HDWriteCORBSync(cad,nid,VERB_EAPDBTL_ENABLE_SET+0x02);
|
||||
HDWriteCORBSync(cad,nid,VERB_PROCESS_STATE_SET+0x02);
|
||||
HDWriteCORBSync(cad,nid,VERB_CONNECT_SEL_SET+0x00);
|
||||
aud_cap=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_SUBNODE_CNT);
|
||||
if (aud_cap.u16[0]) {
|
||||
for (i=aud_cap.u16[1];i<aud_cap.u16[1]+aud_cap.u16[0];i++)
|
||||
HDTraverse(cad,i);
|
||||
} else {
|
||||
aud_cap=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_AUDIO_WIDGET_CAP);
|
||||
type=aud_cap>>20&15;
|
||||
if (Bt(&aud_cap,8))
|
||||
len=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_CONNECT_LST_LEN)&127;
|
||||
else
|
||||
len=0;
|
||||
HDWriteCORBSync(cad,nid,VERB_AMPLIFIER_GAIN_SET+0xF07F); //set I/O amp #0
|
||||
for (i=1;i<len;i++)
|
||||
//Set IN amps to mute
|
||||
HDWriteCORBSync(cad,nid,VERB_AMPLIFIER_GAIN_SET+0x7080+i<<8);
|
||||
switch (type) {
|
||||
case AWT_OUTPUT:
|
||||
if (FALSE) //if disabled
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x00);
|
||||
else
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x10);
|
||||
HDWriteCORBSync(cad,nid,VERB_STREAM_FMT_SET+HD_DFT_OUT_FMT);
|
||||
HDWriteCORBSync(cad,nid,VERB_PROCESS_STATE_SET+0x01);
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
if (TRUE) //if disabled
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x00);
|
||||
else
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x20);
|
||||
HDWriteCORBSync(cad,nid,VERB_STREAM_FMT_SET+HD_DFT_IN_FMT);
|
||||
HDWriteCORBSync(cad,nid,VERB_PROCESS_STATE_SET+0x01);
|
||||
break;
|
||||
case AWT_PIN_COMPLEX:
|
||||
HDWriteCORBSync(cad,nid,VERB_PIN_WIDGET_CTL_SET+0xE2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDRun(Bool in,Bool out)
|
||||
{
|
||||
U32 *_d;
|
||||
if (hda.bar) {
|
||||
if (out) {
|
||||
_d=hda.bar+OSTR0+STRCTL;
|
||||
*_d=0x100002;
|
||||
hda.out_running=TRUE;
|
||||
}
|
||||
if (in) {
|
||||
_d=hda.bar+ISTR0+STRCTL;
|
||||
*_d=0x200002;
|
||||
hda.in_running=TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDStop(Bool in,Bool out)
|
||||
{
|
||||
U32 *_d;
|
||||
if (hda.bar) {
|
||||
if (out) {
|
||||
_d=hda.bar+OSTR0+STRCTL;
|
||||
*_d=0;
|
||||
hda.out_running=FALSE;
|
||||
}
|
||||
if (in) {
|
||||
_d=hda.bar+ISTR0+STRCTL;
|
||||
*_d=0;
|
||||
hda.in_running=FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDSnd(F64 freq,I64 waveform=WF_SQUARE,F64 amp=1.0)
|
||||
{
|
||||
hda.waveform=waveform;
|
||||
hda.amp=amp;
|
||||
hda.freq=freq;
|
||||
}
|
||||
|
||||
U0 HDFillBuf(SND_OUT_CONTAINER *buf,I64)
|
||||
{
|
||||
I64 i,size=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
if (!hda.o_tmp_buf)
|
||||
hda.o_tmp_buf=AMAlloc(size);
|
||||
MemSet(hda.o_tmp_buf,0,size);
|
||||
for (i=0;i<HD_TONES;i++)
|
||||
SndWaveAddBuf(hda.tone_swcs[i],hda.o_tmp_buf,
|
||||
SND_BUF_LEN/SND_OCHANNELS,hda.freq,
|
||||
hda.waveform,snd_vol*hda.amp);
|
||||
MemCpy(buf,hda.o_tmp_buf,size);
|
||||
}
|
||||
|
||||
U0 HDAudioTaskEndCB()
|
||||
{
|
||||
I64 i;
|
||||
HDStop(FALSE,TRUE);
|
||||
fp_snd=NULL;
|
||||
for (i=0;i<HD_TONES;i++) {
|
||||
SndWaveCtrlDel(hda.tone_swcs[i]);
|
||||
hda.tone_swcs[i]=NULL;
|
||||
}
|
||||
Exit;
|
||||
}
|
||||
|
||||
public U0 HDTonesInit()
|
||||
{
|
||||
I64 i;
|
||||
if (hda.bar) {
|
||||
for (i=0;i<HD_TONES;i++) {
|
||||
hda.tone_swcs[i]->freq_multiplier=1.0;
|
||||
hda.tone_swcs[i]->amp_multiplier=0;
|
||||
}
|
||||
hda.tone_swcs[0]->amp_multiplier=1.0;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDAudioTask(I64)
|
||||
{
|
||||
//I didn't feel like messing around with PCI interrupts
|
||||
//so this task polls every millisecond to know when to
|
||||
//switch buffers.
|
||||
I64 i,next_obuf_trigger=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER)/2,
|
||||
obuf_rollover=0,
|
||||
next_ibuf_trigger=SND_BUF_LEN*sizeof(SND_IN_CONTAINER),
|
||||
ibuf_rollover=0;
|
||||
U32 *pos_in_obuf=hda.bar+OSTR0+STRLPIB,
|
||||
*pos_in_ibuf=hda.bar+ISTR0+STRLPIB;
|
||||
Fs->task_end_cb=&HDAudioTaskEndCB;
|
||||
for (i=0;i<HD_TONES;i++)
|
||||
hda.tone_swcs[i]=SndWaveCtrlNew;
|
||||
HDTonesInit;
|
||||
hda.freq=0;
|
||||
Snd;
|
||||
fp_snd=&HDSnd;
|
||||
fp_snd_fill_buf=&HDFillBuf;
|
||||
fp_snd_copy_buf=NULL;
|
||||
snd_obuf_num=1;
|
||||
snd_ibuf_num=1;
|
||||
HDRun(FALSE,TRUE);
|
||||
hda.audio_task_started=TRUE; //This flag is probably not necessary
|
||||
while (TRUE) {
|
||||
if (next_obuf_trigger-obuf_rollover<=*pos_in_obuf<
|
||||
next_obuf_trigger-obuf_rollover+
|
||||
(HD_POS_BUF_MULTIPLES-1)*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER)) {
|
||||
next_obuf_trigger+=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
if (next_obuf_trigger-obuf_rollover>=
|
||||
HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER))
|
||||
obuf_rollover+=HD_POS_BUF_MULTIPLES*SND_BUF_LEN
|
||||
*sizeof(SND_OUT_CONTAINER);
|
||||
if (fp_snd_fill_buf) {
|
||||
LBts(&snd_flags,Sf_FILLING_OUT);
|
||||
(*fp_snd_fill_buf)(hda.ostr0_buf[snd_obuf_num&1],snd_obuf_num);
|
||||
if (IsMute)
|
||||
MemSet(hda.ostr0_buf[snd_obuf_num&1],0,
|
||||
SND_BUF_LEN*sizeof(SND_OUT_CONTAINER));
|
||||
LBtr(&snd_flags,Sf_FILLING_OUT);
|
||||
}
|
||||
snd_obuf_num++;
|
||||
}
|
||||
if (next_ibuf_trigger-ibuf_rollover<=*pos_in_ibuf<
|
||||
next_ibuf_trigger-ibuf_rollover+(HD_POS_BUF_MULTIPLES-1)
|
||||
*SND_BUF_LEN*sizeof(SND_IN_CONTAINER)) {
|
||||
next_ibuf_trigger+=SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
if (next_ibuf_trigger-ibuf_rollover>=
|
||||
HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_IN_CONTAINER))
|
||||
ibuf_rollover+=HD_POS_BUF_MULTIPLES*SND_BUF_LEN
|
||||
*sizeof(SND_IN_CONTAINER);
|
||||
if (fp_snd_copy_buf)
|
||||
(*fp_snd_copy_buf)(hda.istr0_buf[snd_obuf_num&1],snd_ibuf_num);
|
||||
snd_ibuf_num++;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDRst()
|
||||
{
|
||||
U32 d,*_d;
|
||||
HDStop(TRUE,TRUE);
|
||||
_d=hda.bar+HD_GCTL;
|
||||
*_d=0; //rst
|
||||
do {
|
||||
Sleep(1);
|
||||
d=*_d;
|
||||
} while (d & 1);
|
||||
*_d=1;
|
||||
do {
|
||||
Sleep(1);
|
||||
d=*_d;
|
||||
} while (!(d & 1));
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
public U0 HDAudioEnd(Bool rst=TRUE)
|
||||
{
|
||||
snd_dev=SD_PC_SPEAKER;
|
||||
if (hda.bar) {
|
||||
Kill(hda.task);
|
||||
hda.task=NULL;
|
||||
if (rst)
|
||||
HDRst;
|
||||
Free(hda.corb);
|
||||
Free(hda.rirb);
|
||||
Free(hda.o_tmp_buf);
|
||||
Free(hda.ostr0_buf[0]);
|
||||
Free(hda.ostr0_buf[1]);
|
||||
Free(hda.istr0_buf[0]);
|
||||
Free(hda.istr0_buf[1]);
|
||||
Free(hda.ostr0_bdl);
|
||||
Free(hda.istr0_bdl);
|
||||
Mem32DevFree(hda.bar);
|
||||
hda.bar=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDAudioUncachedInit()
|
||||
{
|
||||
I64 shared_blks=1;
|
||||
hda.bp=Mem2MegUncachedAlloc(&shared_blks);
|
||||
hda.hc=HeapCtrlBPInit(hda.bp,shared_blks<<12);
|
||||
}
|
||||
|
||||
public Bool HDAudioInit(I64 hd_bus,I64 hd_dev,I64 hd_fun)
|
||||
{
|
||||
I64 i;
|
||||
U32 *_d;
|
||||
U16 w,*_w;
|
||||
U8 *_b;
|
||||
if (hda.bar)
|
||||
HDAudioEnd;
|
||||
else
|
||||
HDAudioUncachedInit;
|
||||
if (PCIReadU16(hd_bus,hd_dev,hd_fun,0)==0x8086 &&
|
||||
(hda.bar=PCIReadU32(hd_bus,hd_dev,hd_fun,0x10) & ~(0x1F))) {
|
||||
PCIWriteU16(hd_bus,hd_dev,hd_fun,0x04,
|
||||
PCIReadU16(hd_bus,hd_dev,hd_fun,0x04)|0x406);
|
||||
|
||||
HDRst;
|
||||
|
||||
hda.corb=CAllocAligned(HD_CORB_ENTRIES*sizeof(U32),128,hda.hc);
|
||||
_d=hda.bar+HD_CORBLBASE;
|
||||
*_d=hda.corb(I64).u32[0];
|
||||
_d=hda.bar+HD_CORBUBASE;
|
||||
*_d=hda.corb(I64).u32[1];
|
||||
|
||||
hda.rirb=CAllocAligned(HD_RIRB_ENTRIES*sizeof(I64),128,hda.hc);
|
||||
_d=hda.bar+HD_RIRBLBASE;
|
||||
*_d=hda.rirb(I64).u32[0];
|
||||
_d=hda.bar+HD_RIRBUBASE;
|
||||
*_d=hda.rirb(I64).u32[1];
|
||||
|
||||
_w=hda.bar+HD_CORBRP;
|
||||
/*
|
||||
*_w=0x8000; //Rst read ptr
|
||||
do {
|
||||
Yield;
|
||||
w=*_w;
|
||||
} while (!(w&0x8000));
|
||||
*/
|
||||
*_w=0x0000; //Rst read ptr
|
||||
do {
|
||||
Yield;
|
||||
w=*_w;
|
||||
} while (w&0x8000);
|
||||
|
||||
_w=hda.bar+HD_RIRBWP;
|
||||
*_w=0x8000; //Rst write ptr
|
||||
|
||||
_b=hda.bar+HD_CORBCTL;
|
||||
*_b=0x02; //Run
|
||||
_b=hda.bar+HD_RIRBCTL;
|
||||
*_b=0x02; //Run
|
||||
|
||||
_w=hda.bar+HD_CORBWP;
|
||||
hda.corb_wp=*_w;
|
||||
_w=hda.bar+HD_RIRBWP;
|
||||
hda.rirb_rp=*_w;
|
||||
|
||||
hda.ostr0_bdl =CAllocAligned(
|
||||
HD_BDL_ENTRIES*sizeof(CHDBufDesc),128,hda.hc);
|
||||
_d=hda.bar+OSTR0+STRBDPL;
|
||||
*_d=hda.ostr0_bdl(I64).u32[0];
|
||||
_d=hda.bar+OSTR0+STRBDPU;
|
||||
*_d=hda.ostr0_bdl(I64).u32[1];
|
||||
for (i=0;i<2;i++) {
|
||||
hda.ostr0_bdl[i].buf=hda.ostr0_buf[i]=
|
||||
CAllocAligned(
|
||||
SND_BUF_LEN*sizeof(SND_OUT_CONTAINER),128,hda.hc);
|
||||
hda.ostr0_bdl[i].len=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
hda.ostr0_bdl[i].ctrl=1;
|
||||
}
|
||||
|
||||
hda.istr0_bdl =CAllocAligned(
|
||||
HD_BDL_ENTRIES*sizeof(CHDBufDesc),128,hda.hc);
|
||||
_d=hda.bar+ISTR0+STRBDPL;
|
||||
*_d=hda.istr0_bdl(I64).u32[0];
|
||||
_d=hda.bar+ISTR0+STRBDPU;
|
||||
*_d=hda.istr0_bdl(I64).u32[1];
|
||||
for (i=0;i<2;i++) {
|
||||
hda.istr0_bdl[i].buf=hda.istr0_buf[i]=CAllocAligned(
|
||||
SND_BUF_LEN*sizeof(SND_IN_CONTAINER),128,hda.hc);
|
||||
hda.istr0_bdl[i].len=SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
hda.istr0_bdl[i].ctrl=1;
|
||||
}
|
||||
|
||||
_w=hda.bar+HD_STATESTS;
|
||||
w=*_w;
|
||||
while (w) {
|
||||
hda.cad=Bsf(w);
|
||||
if (HDTestCORBSync(hda.cad,0,VERB_GET_PARAM+P_SUBNODE_CNT)) {
|
||||
HDTraverse(hda.cad,0);
|
||||
|
||||
_d=hda.bar+OSTR0+STRLPIB;
|
||||
*_d=0;
|
||||
_d=hda.bar+OSTR0+STRCBL;
|
||||
*_d=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
_w=hda.bar+OSTR0+STRLVI;
|
||||
*_w=1; //last valid idx
|
||||
_w=hda.bar+OSTR0+STRFMT;
|
||||
*_w=HD_DFT_OUT_FMT;
|
||||
|
||||
_d=hda.bar+ISTR0+STRLPIB;
|
||||
*_d=0;
|
||||
_d=hda.bar+ISTR0+STRCBL;
|
||||
*_d=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
_w=hda.bar+ISTR0+STRLVI;
|
||||
*_w=1; //last valid idx
|
||||
_w=hda.bar+ISTR0+STRFMT;
|
||||
*_w=HD_DFT_IN_FMT;
|
||||
|
||||
LBts(&sys_semas[SEMA_SND],0); //turn off until cfg completed
|
||||
LBtr(&snd_flags,Sf_FILLING_OUT);
|
||||
hda.audio_task_started=FALSE;
|
||||
if (mp_cnt>1)
|
||||
hda.task=Spawn(&HDAudioTask,NULL,"HD Audio",mp_cnt-1);
|
||||
else
|
||||
hda.task=Spawn(&HDAudioTask,NULL,"HD Audio");
|
||||
while (!hda.audio_task_started)
|
||||
Yield;
|
||||
snd_dev=SD_HD_AUDIO;
|
||||
return TRUE;
|
||||
}
|
||||
Btr(&w,hda.cad);
|
||||
}
|
||||
HDAudioEnd(FALSE);
|
||||
} else
|
||||
hda.bar=NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool HDAudioScan()
|
||||
{
|
||||
I64 i=-1,j;
|
||||
while (TRUE) {
|
||||
j=PCIClassFind(0x040300,++i);
|
||||
if (j<0)
|
||||
return FALSE;
|
||||
|
||||
if (HDAudioInit(j.u8[2],j.u8[1],j.u8[0]))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
HDAudioScan;
|
||||
Kill(hda.task);
|
||||
HDAudioScan;
|
||||
@@ -1,12 +1,32 @@
|
||||
#include "HDAudio";
|
||||
|
||||
// vim: set ft=c:
|
||||
|
||||
#ifndef SND_BUF_LEN
|
||||
#define SND_BUF_LEN 0
|
||||
U64 snd_obuf_num;
|
||||
U64 fp_snd_fill_buf;
|
||||
#endif
|
||||
|
||||
#ifndef SND_OUT_CONTAINER
|
||||
#define SND_OUT_CONTAINER U32
|
||||
#endif
|
||||
|
||||
U8 *rom_filename=NULL;
|
||||
Bool rom_select=FALSE;
|
||||
|
||||
CDoc *doc_tmp=DocNew;
|
||||
CDoc *doc_prev=Fs->put_doc;
|
||||
|
||||
CTask *draw_task=NULL;
|
||||
CTask *emu_task=NULL;
|
||||
CTask *sys_task=NULL;
|
||||
|
||||
CSprite *vid;
|
||||
CDC *gameCanvas=DCNew(320,240);
|
||||
CDC *Canvas16=DCNew(320,240);
|
||||
DCFill(gameCanvas,0);
|
||||
DCFill(Canvas16);
|
||||
|
||||
CDC *scr_pillar = DCNew(32,200);
|
||||
DCFill(scr_pillar,0);
|
||||
@@ -36,12 +56,13 @@ U8 frame_finished=0;
|
||||
U8 tmp_str[256];
|
||||
|
||||
#include "TOSGame";
|
||||
#include "Font";
|
||||
#include "GUI";
|
||||
|
||||
//Hide 64-bit reg var compiler warnings.
|
||||
Fs->put_doc=doc_tmp;
|
||||
//Fs->put_doc=doc_tmp;
|
||||
|
||||
U8 *cartridgebuffer;
|
||||
U8 *cartridgebuffer=NULL;
|
||||
|
||||
I64 numPRGROM;
|
||||
I64 numCHRROM;
|
||||
@@ -50,44 +71,97 @@ I64 controlByte2;
|
||||
I64 numRAM;
|
||||
I64 trainer;
|
||||
I64 mapper;
|
||||
I64 mirroringType;
|
||||
|
||||
Bool papu_request_irq = FALSE;
|
||||
Bool mapper_request_irq = FALSE;
|
||||
|
||||
#define MIRR_HORZ 0
|
||||
#define MIRR_VERT 1
|
||||
#define MIRR_SINGLE 2
|
||||
|
||||
#include "Gamepad";
|
||||
#include "Joypad";
|
||||
#include "Mappers";
|
||||
#include "PAPU";
|
||||
#include "MMU";
|
||||
#include "CPU";
|
||||
#include "PPU";
|
||||
#include "Audio";
|
||||
|
||||
U0 handleResetButton()
|
||||
initMMU();
|
||||
|
||||
U8 *system_state=MAlloc(0x200FD);
|
||||
|
||||
/*
|
||||
U0 SaveInitSystemState()
|
||||
{
|
||||
if (TG_KeyDown(Char2ScanCode('r')))
|
||||
{
|
||||
frame_count=0;
|
||||
reset6502;
|
||||
MemCpy(system_state, MMU.RAM, 0xFFFF);
|
||||
MemCpy(system_state+0xFFFF, MMU.VRAM, 0xFFFF);
|
||||
MemCpy(system_state+(0xFFFF*2), MMU.OAM, 0xFF);
|
||||
FileWrite("E:/Home/Src/templenes/State.BIN.Z",system_state,0x200FD);
|
||||
}
|
||||
*/
|
||||
|
||||
//initalize the PPU
|
||||
initPPU2C02(&PPU_state);
|
||||
|
||||
//initalize the Joypad
|
||||
initJoypad(&NES_Joypad);
|
||||
}
|
||||
if (TG_KeyDown(Char2ScanCode('d')))
|
||||
U0 LoadInitSystemState()
|
||||
{
|
||||
if (system_state)
|
||||
{
|
||||
TG_Exit;
|
||||
Dbg;
|
||||
//Free(system_state);
|
||||
}
|
||||
system_state=FileRead("E:/Home/Src/templenes/State.BIN.Z");
|
||||
MemCpy(MMU.RAM, system_state, 0xFFFF);
|
||||
MemCpy(MMU.VRAM, system_state+0xFFFF, 0xFFFF);
|
||||
MemCpy(MMU.OAM, system_state+(0xFFFF*2), 0xFF);
|
||||
MemCpy(system_state+0xFFFF, MMU.VRAM, 0xFFFF);
|
||||
MemCpy(system_state+(0xFFFF*2), MMU.OAM, 0xFF);
|
||||
//Free(system_state);
|
||||
system_state=NULL;
|
||||
}
|
||||
|
||||
U0 resetSystem()
|
||||
{
|
||||
frame_count=0;
|
||||
reset6502;
|
||||
//initalize the PPU
|
||||
initPPU2C02(&PPU_state);
|
||||
//initalize the Joypad
|
||||
initJoypad(&NES_Joypad);
|
||||
//initialize the pAPU
|
||||
if (SND_BUF_LEN>0)
|
||||
{
|
||||
PAPU_reset(&PAPU);
|
||||
}
|
||||
}
|
||||
|
||||
U0 handleCmdButtons()
|
||||
{
|
||||
if (TG_KeyDown(SC_ESC))
|
||||
{
|
||||
quit=TRUE;
|
||||
}
|
||||
if (TG_KeyDown(Char2ScanCode('r')))
|
||||
{
|
||||
resetSystem;
|
||||
}
|
||||
if (TG_KeyDown(Char2ScanCode('d')))
|
||||
{
|
||||
paused = TRUE;
|
||||
fp_snd_fill_buf=fp_old_fill_buf;
|
||||
Sleep(100);//Give time to switch audio callback
|
||||
TG_Exit;
|
||||
Dbg;
|
||||
fp_snd_fill_buf=&AudioFillBuf;
|
||||
paused = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 doScreenUpdate()
|
||||
{
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{
|
||||
GrBlot(gameCanvas, 0, -8, Canvas16);
|
||||
DCFill(Canvas16);
|
||||
}
|
||||
if (fit_screen)
|
||||
{
|
||||
vid=DC2Sprite(gameCanvas);
|
||||
@@ -108,7 +182,12 @@ U0 drawScreen()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
|
||||
WinMsUpdate;
|
||||
KbdMsHndlr(FALSE, FALSE);
|
||||
|
||||
if( frame_finished ) {
|
||||
updateGamepad;
|
||||
frame_count += 1;
|
||||
doScreenUpdate;
|
||||
}
|
||||
@@ -119,22 +198,17 @@ U0 drawScreen()
|
||||
}
|
||||
}
|
||||
|
||||
I64 TempleNES(U8 *rom_filename)
|
||||
U0 initCart(U8 *rom_filename)
|
||||
{
|
||||
CDirEntry *chk_file=FilesFind(rom_filename);
|
||||
if( !chk_file ) {
|
||||
PrintErr("iNES ROM file not found.\n");
|
||||
return 1;
|
||||
}
|
||||
DirTreeDel(chk_file);
|
||||
|
||||
cartridgebuffer = FileRead(rom_filename);
|
||||
|
||||
//if the file is not an iNES-file, abort
|
||||
if(cartridgebuffer[0] != 'N' || cartridgebuffer[1] != 'E' || cartridgebuffer[2] != 'S' || cartridgebuffer[3] != 0x1a) {
|
||||
PrintErr("File is not an iNES-file.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mirroringType = MIRR_HORZ;
|
||||
numPRGROM = cartridgebuffer[4];
|
||||
numCHRROM = cartridgebuffer[5];
|
||||
controlByte1 = cartridgebuffer[6];
|
||||
@@ -143,9 +217,14 @@ I64 TempleNES(U8 *rom_filename)
|
||||
|
||||
trainer = (controlByte1 & (1 << 2));
|
||||
|
||||
if (controlByte1 & 1)
|
||||
{
|
||||
mirroringType = MIRR_VERT;
|
||||
}
|
||||
|
||||
mapper = ( (controlByte2 & 0xF0) | ((controlByte1 & 0xF0) >> 4));
|
||||
|
||||
initMMU();
|
||||
//LoadInitSystemState;
|
||||
|
||||
switch (mapper)
|
||||
{
|
||||
@@ -158,18 +237,67 @@ I64 TempleNES(U8 *rom_filename)
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000*numCHRROM);
|
||||
break;
|
||||
case 1:
|
||||
case 1:// MMC1
|
||||
case 2:// UNROM
|
||||
//Load first PRG ROM bank
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10, 0x4000);
|
||||
//and last PRG ROM bank
|
||||
MemCpy(MMU.RAM+0xC000, cartridgebuffer+0x10+0x4000*(numPRGROM-1), 0x4000);
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000*numCHRROM);
|
||||
if (numCHRROM)
|
||||
{
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000*numCHRROM);
|
||||
}
|
||||
break;
|
||||
case 3:// CNROM
|
||||
//Copy the ROM into the CPU's memory
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10, numPRGROM*0x4000);
|
||||
if(numPRGROM == 1) {
|
||||
MemCpy(MMU.RAM+0xC000, cartridgebuffer+0x10, numPRGROM*0x4000);
|
||||
}
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000);
|
||||
break;
|
||||
case 4:// MMC3
|
||||
MMC1_load8kRomBank((numPRGROM - 1) * 2, 0xc000);
|
||||
MMC1_load8kRomBank((numPRGROM - 1) * 2 + 1, 0xe000);
|
||||
MMC1_load8kRomBank(0, 0x8000);
|
||||
MMC1_load8kRomBank(1, 0xa000);
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000);
|
||||
break;
|
||||
case 11:// Color Dreams
|
||||
//Load first PRG ROM bank
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10, 0x8000);
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000);
|
||||
break;
|
||||
case 17:// FFE Copier
|
||||
//Load first PRG ROM bank
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10, 0x8000);
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000);
|
||||
break;
|
||||
case 18:// Jaleco SS88006
|
||||
//Load first/last PRG ROM bank
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10, 0x4000);
|
||||
MemCpy(MMU.RAM+0xC000, cartridgebuffer+0x10+(0x4000*(numPRGROM-1)), 0x4000);
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+0x4000*numPRGROM, 0x2000);
|
||||
break;
|
||||
default:
|
||||
PrintErr("iNES mapper not supported.\n");
|
||||
//Free(cartridgebuffer);
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
I64 TempleNES(U8 *rom_file)
|
||||
{
|
||||
initCart(rom_file);
|
||||
|
||||
//initalize the CPU
|
||||
reset6502;
|
||||
|
||||
@@ -179,6 +307,12 @@ I64 TempleNES(U8 *rom_filename)
|
||||
//initalize the Joypad
|
||||
initJoypad(&NES_Joypad);
|
||||
|
||||
//initialize the pAPU
|
||||
if (SND_BUF_LEN>0)
|
||||
{
|
||||
initPAPU(&PAPU);
|
||||
}
|
||||
|
||||
//Initalize TOSGame
|
||||
TG_Start;
|
||||
|
||||
@@ -187,38 +321,58 @@ I64 TempleNES(U8 *rom_filename)
|
||||
|
||||
draw_task = Spawn(&drawScreen,,,1);
|
||||
|
||||
while(!quit) {
|
||||
WinMsUpdate;
|
||||
KbdMsHndlr(FALSE, FALSE);
|
||||
|
||||
start_buf_num=snd_obuf_num;
|
||||
fp_old_fill_buf=fp_snd_fill_buf;
|
||||
fp_snd_fill_buf=&AudioFillBuf;
|
||||
|
||||
while(!quit && !TG_KeyDown(SC_ESC)) {
|
||||
//emulate CPU and PPU
|
||||
frame_finished = 0;
|
||||
|
||||
if( paused == 0 ) {
|
||||
if( paused == 0) {
|
||||
if (mapper_request_irq)
|
||||
{
|
||||
irq6502;
|
||||
mapper_request_irq = FALSE;
|
||||
}
|
||||
if (papu_request_irq)
|
||||
{
|
||||
irq6502;
|
||||
papu_request_irq = FALSE;
|
||||
}
|
||||
exec6502(1);
|
||||
cycles = ticktable[opcode];
|
||||
if (SND_BUF_LEN>0)
|
||||
{
|
||||
PAPU_clockFrameCounter(&PAPU, cycles);
|
||||
}
|
||||
loop = cycles*3;
|
||||
while( loop != 0 )
|
||||
{
|
||||
frame_finished |= PPUcycle(&PPU_state);
|
||||
loop -= 1;
|
||||
}
|
||||
I64 ii;
|
||||
for (ii=0;ii<1024;ii++){} // Delay loop
|
||||
}
|
||||
|
||||
if (reset)
|
||||
{
|
||||
resetSystem;
|
||||
reset = FALSE;
|
||||
}
|
||||
handleResetButton;
|
||||
handleCmdButtons;
|
||||
handleInput(&NES_Joypad);
|
||||
}
|
||||
quit = FALSE;
|
||||
fp_snd_fill_buf=fp_old_fill_buf;
|
||||
Kill(draw_task);
|
||||
DocClear;
|
||||
Free(cartridgebuffer);
|
||||
//Free(cartridgebuffer);
|
||||
TG_Exit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Fs->put_doc=doc_prev;
|
||||
Fs->put_doc=doc_prev;
|
||||
|
||||
start_buf_num=snd_obuf_num;
|
||||
fp_old_fill_buf=fp_snd_fill_buf;
|
||||
|
||||
@@ -8,6 +8,8 @@ U8 byte2;
|
||||
|
||||
U8 shift_register_0;
|
||||
U8 shift_register_1;
|
||||
U8 shift_register_2;
|
||||
U8 shift_register_3;
|
||||
U8 attribute;
|
||||
U8 x;
|
||||
};
|
||||
@@ -29,234 +31,33 @@ U16 nametable_base;
|
||||
|
||||
U16 bitmap_shift_0_latch;
|
||||
U16 bitmap_shift_1_latch;
|
||||
U16 bitmap_shift_2_latch;
|
||||
U16 bitmap_shift_3_latch;
|
||||
|
||||
U16 bitmap_shift_0;
|
||||
U16 bitmap_shift_1;
|
||||
|
||||
U16 bitmap_shift_2;
|
||||
U16 bitmap_shift_3;
|
||||
|
||||
U16 AT_shift_0_latch;
|
||||
U16 AT_shift_1_latch;
|
||||
U16 AT_shift_0;
|
||||
U16 AT_shift_1;
|
||||
|
||||
U16 AT_shift_2_latch;
|
||||
U16 AT_shift_3_latch;
|
||||
U16 AT_shift_2;
|
||||
U16 AT_shift_3;
|
||||
|
||||
U8 num_sprites;
|
||||
PPUsprite sprites[8];
|
||||
};
|
||||
|
||||
PPU2C02state PPU_state;
|
||||
|
||||
class memory_manager {
|
||||
U8 *RAM;
|
||||
U8 *VRAM;
|
||||
U8 *OAM;
|
||||
|
||||
U8 w;
|
||||
U16 t;
|
||||
U16 x;
|
||||
U16 y;
|
||||
|
||||
U16 VRAM_address;
|
||||
U8 internal_buffer;
|
||||
};
|
||||
|
||||
memory_manager MMU;
|
||||
|
||||
// Mapper #1 [MMC1]
|
||||
|
||||
// 5-bit buffer:
|
||||
I64 MMC1_regBuffer = 0;
|
||||
I64 MMC1_regBufferCounter = 0;
|
||||
// Register 0:
|
||||
I64 MMC1_mirroring = 0;
|
||||
I64 MMC1_oneScreenMirroring = 0;
|
||||
I64 MMC1_prgSwitchingArea = 1;
|
||||
I64 MMC1_prgSwitchingSize = 1;
|
||||
I64 MMC1_vromSwitchingSize = 0;
|
||||
// Register 1:
|
||||
I64 MMC1_romSelectionReg0 = 0;
|
||||
// Register 2:
|
||||
I64 MMC1_romSelectionReg1 = 0;
|
||||
// Register 3:
|
||||
I64 MMC1_romBankSelect = 0;
|
||||
|
||||
I64 MMC1_getRegNumber(U16 address)
|
||||
{
|
||||
if (address >= 0x8000 && address <= 0x9fff) {
|
||||
return 0;
|
||||
} else if (address >= 0xa000 && address <= 0xbfff) {
|
||||
return 1;
|
||||
} else if (address >= 0xc000 && address <= 0xdfff) {
|
||||
return 2;
|
||||
} else {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
U0 MMC1_loadRomBank(I64 bank, U16 address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
U0 MMC1_loadVromBank(I64 bank, U16 address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
U0 MMC1_load32kRomBank(I64 bank, U16 address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
U0 MMC1_load8kVromBank(I64 bank, U16 address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
U0 MMC1_setReg(I64 _reg, I64 value)
|
||||
{
|
||||
I64 tmp;
|
||||
switch (_reg) {
|
||||
case 0:
|
||||
// Mirroring:
|
||||
tmp = value & 3;
|
||||
if (tmp != MMC1_mirroring) {
|
||||
// Set mirroring:
|
||||
MMC1_mirroring = tmp;
|
||||
/* TODO: mirroring
|
||||
if ((MMC1_mirroring & 2) == 0) {
|
||||
// SingleScreen mirroring overrides the other setting:
|
||||
MMC1_nes.ppu.setMirroring(MMC1_nes.rom.SINGLESCREEN_MIRRORING);
|
||||
} else if ((MMC1_mirroring & 1) != 0) {
|
||||
// Not overridden by SingleScreen mirroring.
|
||||
MMC1_nes.ppu.setMirroring(MMC1_nes.rom.HORIZONTAL_MIRRORING);
|
||||
} else {
|
||||
MMC1_nes.ppu.setMirroring(MMC1_nes.rom.VERTICAL_MIRRORING);
|
||||
}
|
||||
*/
|
||||
}
|
||||
// PRG Switching Area;
|
||||
MMC1_prgSwitchingArea = (value >> 2) & 1;
|
||||
// PRG Switching Size:
|
||||
MMC1_prgSwitchingSize = (value >> 3) & 1;
|
||||
// VROM Switching Size:
|
||||
MMC1_vromSwitchingSize = (value >> 4) & 1;
|
||||
break;
|
||||
case 1:
|
||||
// ROM selection:
|
||||
MMC1_romSelectionReg0 = (value >> 4) & 1;
|
||||
// Check whether the cart has VROM:
|
||||
if (numCHRROM > 0) {
|
||||
// Select VROM bank at 0x0000:
|
||||
if (MMC1_vromSwitchingSize == 0) {
|
||||
// Swap 8kB VROM:
|
||||
if (MMC1_romSelectionReg0 == 0) {
|
||||
MMC1_load8kVromBank(value & 0xf, 0x0000);
|
||||
} else {
|
||||
MMC1_load8kVromBank(
|
||||
Floor(numCHRROM / 2) + (value & 0xf),
|
||||
0x0000
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Swap 4kB VROM:
|
||||
if (MMC1_romSelectionReg0 == 0) {
|
||||
MMC1_loadVromBank(value & 0xf, 0x0000);
|
||||
} else {
|
||||
MMC1_loadVromBank(
|
||||
Floor(numCHRROM / 2) + (value & 0xf),
|
||||
0x0000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// ROM selection:
|
||||
MMC1_romSelectionReg1 = (value >> 4) & 1;
|
||||
// Check whether the cart has VROM:
|
||||
if (numCHRROM > 0) {
|
||||
// Select VROM bank at 0x1000:
|
||||
if (MMC1_vromSwitchingSize == 1) {
|
||||
// Swap 4kB of VROM:
|
||||
if (MMC1_romSelectionReg1 == 0) {
|
||||
MMC1_loadVromBank(value & 0xf, 0x1000);
|
||||
} else {
|
||||
MMC1_loadVromBank(
|
||||
Floor(numCHRROM / 2) + (value & 0xf),
|
||||
0x1000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Select ROM bank:
|
||||
// -------------------------
|
||||
tmp = value & 0xf;
|
||||
I64 bank;
|
||||
I64 baseBank = 0;
|
||||
if (numPRGROM >= 32) {
|
||||
// 1024 kB cart
|
||||
if (MMC1_vromSwitchingSize == 0) {
|
||||
if (MMC1_romSelectionReg0 == 1) {
|
||||
baseBank = 16;
|
||||
}
|
||||
} else {
|
||||
baseBank =
|
||||
(MMC1_romSelectionReg0 | (MMC1_romSelectionReg1 << 1)) << 3;
|
||||
}
|
||||
} else if (numPRGROM >= 16) {
|
||||
// 512 kB cart
|
||||
if (MMC1_romSelectionReg0 == 1) {
|
||||
baseBank = 8;
|
||||
}
|
||||
}
|
||||
if (MMC1_prgSwitchingSize == 0) {
|
||||
// 32kB
|
||||
bank = baseBank + (value & 0xf);
|
||||
MMC1_load32kRomBank(bank, 0x8000);
|
||||
} else {
|
||||
// 16kB
|
||||
bank = baseBank * 2 + (value & 0xf);
|
||||
if (MMC1_prgSwitchingArea == 0) {
|
||||
MMC1_loadRomBank(bank, 0xc000);
|
||||
} else {
|
||||
MMC1_loadRomBank(bank, 0x8000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 MMC1_Write(U16 address, U8 value)
|
||||
{
|
||||
// See what should be done with the written value:
|
||||
if ((value & 128) != 0) {
|
||||
// Reset buffering:
|
||||
MMC1_regBufferCounter = 0;
|
||||
MMC1_regBuffer = 0;
|
||||
// Reset register:
|
||||
if (MMC1_getRegNumber(address) == 0) {
|
||||
MMC1_prgSwitchingArea = 1;
|
||||
MMC1_prgSwitchingSize = 1;
|
||||
}
|
||||
} else {
|
||||
// Continue buffering:
|
||||
//regBuffer = (regBuffer & (0xFF-(1<<regBufferCounter))) | ((value & (1<<regBufferCounter))<<regBufferCounter);
|
||||
MMC1_regBuffer =
|
||||
(MMC1_regBuffer & (0xff - (1 << MMC1_regBufferCounter))) |
|
||||
((value & 1) << MMC1_regBufferCounter);
|
||||
MMC1_regBufferCounter++;
|
||||
if (MMC1_regBufferCounter == 5) {
|
||||
// Use the buffered value:
|
||||
MMC1_setReg(MMC1_getRegNumber(address), MMC1_regBuffer);
|
||||
// Reset buffer:
|
||||
MMC1_regBuffer = 0;
|
||||
MMC1_regBufferCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 initMMU() {
|
||||
MemSet(&PPU_state,0,sizeof(PPU2C02state));
|
||||
|
||||
MMU.RAM = MAlloc(0xFFFF);
|
||||
MMU.VRAM = MAlloc(0xFFFF);
|
||||
MMU.OAM = MAlloc(0xFF);
|
||||
@@ -271,7 +72,32 @@ U0 initMMU() {
|
||||
}
|
||||
|
||||
U0 writeVRAM(U16 address, U8 value) {
|
||||
//assert(address <= 0x3F20);
|
||||
|
||||
if (address > 0x2FFF && address < 0x3F00)
|
||||
{ //Nametable mirror
|
||||
address -= 0x1000;
|
||||
}
|
||||
|
||||
if (mirroringType == MIRR_HORZ)
|
||||
{
|
||||
if (address > 0x23FF && address < 0x2800)
|
||||
{
|
||||
address -= 0x400;
|
||||
}
|
||||
if (address > 0x2BFF && address < 0x3000)
|
||||
{
|
||||
address -= 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
if (mirroringType == MIRR_VERT)
|
||||
{
|
||||
if (address > 0x1FFF && address < 0x3000)
|
||||
{
|
||||
address &= 0x27FF;
|
||||
}
|
||||
}
|
||||
|
||||
MMU.VRAM[address] = value;
|
||||
if( address == 0x3F10 || address == 0x3F14 || address == 0x3F18 || address == 0x3F1C ) {
|
||||
address -= 0x10;
|
||||
@@ -281,7 +107,35 @@ U0 writeVRAM(U16 address, U8 value) {
|
||||
}
|
||||
|
||||
U8 readVRAM(U16 address) {
|
||||
//assert(address <= 0x3F20);
|
||||
|
||||
if (address > 0x2FFF && address < 0x3F00)
|
||||
{ //Nametable mirror
|
||||
address -= 0x1000;
|
||||
}
|
||||
|
||||
if (mirroringType == MIRR_HORZ)
|
||||
{
|
||||
if (address > 0x23FF && address < 0x2800)
|
||||
{
|
||||
address -= 0x400;
|
||||
return MMU.VRAM[address];
|
||||
}
|
||||
if (address > 0x2BFF && address < 0x3000)
|
||||
{
|
||||
address -= 0x400;
|
||||
return MMU.VRAM[address];
|
||||
}
|
||||
}
|
||||
|
||||
if (mirroringType == MIRR_VERT)
|
||||
{
|
||||
if (address > 0x1FFF && address < 0x3000)
|
||||
{
|
||||
address &= 0x27FF;
|
||||
return MMU.VRAM[address];
|
||||
}
|
||||
}
|
||||
|
||||
if( address == 0x3F10 || address == 0x3F14 || address == 0x3F18 || address == 0x3F1C ) {
|
||||
address -= 0x10;
|
||||
}
|
||||
@@ -331,7 +185,6 @@ U8 writeRAM(U16 address, U8 value) {
|
||||
MMU.t &= ~31; // 31 = 11111b
|
||||
MMU.t |= ((value&248) >> 3);
|
||||
MMU.x = (value & 7);
|
||||
//printf("setting coarse X to %d on scanline %d\n", ((value&248) >> 3), PPU_state.scanline);
|
||||
}
|
||||
else {
|
||||
//t: CBA..HG FED..... = d: HGFEDCBA
|
||||
@@ -380,11 +233,34 @@ U8 writeRAM(U16 address, U8 value) {
|
||||
return 513 + PPU_state.odd_frame; //I think?
|
||||
}
|
||||
|
||||
//PAPU
|
||||
if ((address > 0x3FFF && address < 0x4016) || address == 0x4017)
|
||||
{
|
||||
if (SND_BUF_LEN>0)
|
||||
{
|
||||
PAPU_writeReg(&PAPU, address, value);
|
||||
}
|
||||
}
|
||||
|
||||
//Joypad 1
|
||||
else if(address == 0x4016) {
|
||||
writeJoypad(&NES_Joypad, value);
|
||||
}
|
||||
|
||||
else if(address > 0x44FF && address < 0x451D && mapper==17) {
|
||||
FFE_Write(address, value);
|
||||
}
|
||||
|
||||
else if (mapper == 18 && ((address > 0x7FFF && address < 0x8004) ||
|
||||
(address > 0x8FFF && address < 0x9002) ||
|
||||
(address > 0x9FFF && address < 0xA004) ||
|
||||
(address > 0xAFFF && address < 0xB004) ||
|
||||
(address > 0xBFFF && address < 0xC004) ||
|
||||
(address > 0xCFFF && address < 0xD004)))
|
||||
{
|
||||
SS88006_Write(address, value);
|
||||
}
|
||||
|
||||
else if(address > 0x7FFF) {
|
||||
switch (mapper)
|
||||
{
|
||||
@@ -392,6 +268,22 @@ U8 writeRAM(U16 address, U8 value) {
|
||||
MMC1_Write(address, value);
|
||||
return 0;
|
||||
break;
|
||||
case 2:
|
||||
UNROM_Write(address, value);
|
||||
return 0;
|
||||
break;
|
||||
case 3:
|
||||
CNROM_Write(address, value);
|
||||
return 0;
|
||||
break;
|
||||
case 4:
|
||||
MMC3_Write(address, value);
|
||||
return 0;
|
||||
break;
|
||||
case 11:
|
||||
ColorDreams_Write(address, value);
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -402,6 +294,7 @@ U8 writeRAM(U16 address, U8 value) {
|
||||
}
|
||||
|
||||
U8 readRAM(U16 address) {
|
||||
|
||||
while(address >= 0x2008 && address < 0x4000) {
|
||||
address -= 8; //handle mirroring
|
||||
}
|
||||
@@ -451,6 +344,14 @@ U8 readRAM(U16 address) {
|
||||
retVal = getNextButton(&NES_Joypad);
|
||||
}
|
||||
|
||||
//PAPU
|
||||
if ((address > 0x3FFF && address < 0x4016))
|
||||
{
|
||||
if (SND_BUF_LEN>0)
|
||||
{
|
||||
return PAPU_readReg(&PAPU, address);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -493,4 +394,4 @@ U0 dumpVRAM() {
|
||||
"%X, ", MMU.VRAM[address];
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+549
@@ -0,0 +1,549 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
class memory_manager {
|
||||
U8 *RAM;
|
||||
U8 *VRAM;
|
||||
U8 *OAM;
|
||||
|
||||
U8 w;
|
||||
U16 t;
|
||||
U16 x;
|
||||
U16 y;
|
||||
|
||||
U16 VRAM_address;
|
||||
U8 internal_buffer;
|
||||
};
|
||||
|
||||
memory_manager MMU;
|
||||
|
||||
// Mapper #1 [MMC1]
|
||||
|
||||
// 5-bit buffer:
|
||||
I64 MMC1_regBuffer = 0;
|
||||
I64 MMC1_regBufferCounter = 0;
|
||||
// Register 0:
|
||||
I64 MMC1_mirroring = 0;
|
||||
I64 MMC1_oneScreenMirroring = 0;
|
||||
I64 MMC1_prgSwitchingArea = 1;
|
||||
I64 MMC1_prgSwitchingSize = 1;
|
||||
I64 MMC1_vromSwitchingSize = 0;
|
||||
// Register 1:
|
||||
I64 MMC1_romSelectionReg0 = 0;
|
||||
// Register 2:
|
||||
I64 MMC1_romSelectionReg1 = 0;
|
||||
// Register 3:
|
||||
I64 MMC1_romBankSelect = 0;
|
||||
|
||||
I64 MMC1_getRegNumber(U16 address)
|
||||
{
|
||||
if (address >= 0x8000 && address <= 0x9fff) {
|
||||
return 0;
|
||||
} else if (address >= 0xa000 && address <= 0xbfff) {
|
||||
return 1;
|
||||
} else if (address >= 0xc000 && address <= 0xdfff) {
|
||||
return 2;
|
||||
} else {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
U0 MMC1_loadRomBank(I64 bank, U16 address)
|
||||
{
|
||||
// Swap in the given PRG-ROM bank:
|
||||
MemCpy(MMU.RAM+address, cartridgebuffer+0x10+0x4000*(bank), 0x4000);
|
||||
}
|
||||
|
||||
U0 MMC1_loadVromBank(I64 bank, U16 address)
|
||||
{
|
||||
//Copy the ROM into the PPU's memory
|
||||
I64 bank4k = Floor(bank / 4) % numCHRROM;
|
||||
I64 bankoffset = (bank % 4) * 1024;
|
||||
MemCpy(MMU.VRAM+address, cartridgebuffer+0x10+(0x4000*numPRGROM)+(0x1000*(bankoffset)), 1024);
|
||||
}
|
||||
|
||||
U0 MMC1_load1kVromBank(I64 bank, U16 address)
|
||||
{
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM+address, cartridgebuffer+0x10+(0x4000*numPRGROM)+(0x400*(bank)), 0x400);
|
||||
}
|
||||
|
||||
U0 MMC1_load8kRomBank(I64 bank, U16 address)
|
||||
{
|
||||
// Swap in the given PRG-ROM bank:
|
||||
MemCpy(MMU.RAM+address, cartridgebuffer+0x10+0x2000*(bank), 0x2000);
|
||||
}
|
||||
|
||||
U0 MMC1_load32kRomBank(I64 bank, U16 address)
|
||||
{
|
||||
// Swap in the given PRG-ROM bank:
|
||||
MemCpy(MMU.RAM+address, cartridgebuffer+0x10+0x4000*(bank), 0x8000);
|
||||
}
|
||||
|
||||
U0 MMC1_load8kVromBank(I64 bank, U16 address)
|
||||
{
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM+address, cartridgebuffer+0x10+(0x4000*numPRGROM)+(0x1000*(bank)), 0x2000);
|
||||
}
|
||||
|
||||
U0 MMC1_setReg(I64 _reg, I64 value)
|
||||
{
|
||||
I64 tmp;
|
||||
switch (_reg) {
|
||||
case 0:
|
||||
// Mirroring:
|
||||
tmp = value & 3;
|
||||
if (tmp != MMC1_mirroring) {
|
||||
// Set mirroring:
|
||||
MMC1_mirroring = tmp;
|
||||
if ((MMC1_mirroring & 2) == 0) {
|
||||
// SingleScreen mirroring overrides the other setting:
|
||||
mirroringType = MIRR_SINGLE;
|
||||
} else if ((MMC1_mirroring & 1) != 0) {
|
||||
// Not overridden by SingleScreen mirroring.
|
||||
mirroringType = MIRR_HORZ;
|
||||
} else {
|
||||
mirroringType = MIRR_VERT;
|
||||
}
|
||||
}
|
||||
// PRG Switching Area;
|
||||
MMC1_prgSwitchingArea = (value >> 2) & 1;
|
||||
// PRG Switching Size:
|
||||
MMC1_prgSwitchingSize = (value >> 3) & 1;
|
||||
// VROM Switching Size:
|
||||
MMC1_vromSwitchingSize = (value >> 4) & 1;
|
||||
break;
|
||||
case 1:
|
||||
// ROM selection:
|
||||
MMC1_romSelectionReg0 = (value >> 4) & 1;
|
||||
// Check whether the cart has VROM:
|
||||
if (numCHRROM > 0) {
|
||||
// Select VROM bank at 0x0000:
|
||||
if (MMC1_vromSwitchingSize == 0) {
|
||||
// Swap 8kB VROM:
|
||||
if (MMC1_romSelectionReg0 == 0) {
|
||||
MMC1_load8kVromBank(value & 0xf, 0x0000);
|
||||
} else {
|
||||
MMC1_load8kVromBank(
|
||||
Floor(numCHRROM / 2) + (value & 0xf),
|
||||
0x0000
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Swap 4kB VROM:
|
||||
if (MMC1_romSelectionReg0 == 0) {
|
||||
MMC1_loadVromBank(value & 0xf, 0x0000);
|
||||
} else {
|
||||
MMC1_loadVromBank(
|
||||
Floor(numCHRROM / 2) + (value & 0xf),
|
||||
0x0000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// ROM selection:
|
||||
MMC1_romSelectionReg1 = (value >> 4) & 1;
|
||||
// Check whether the cart has VROM:
|
||||
if (numCHRROM > 0) {
|
||||
// Select VROM bank at 0x1000:
|
||||
if (MMC1_vromSwitchingSize == 1) {
|
||||
// Swap 4kB of VROM:
|
||||
if (MMC1_romSelectionReg1 == 0) {
|
||||
MMC1_loadVromBank(value & 0xf, 0x1000);
|
||||
} else {
|
||||
MMC1_loadVromBank(
|
||||
Floor(numCHRROM / 2) + (value & 0xf),
|
||||
0x1000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Select ROM bank:
|
||||
// -------------------------
|
||||
tmp = value & 0xf;
|
||||
I64 bank;
|
||||
I64 baseBank = 0;
|
||||
if (numPRGROM >= 32) {
|
||||
// 1024 kB cart
|
||||
if (MMC1_vromSwitchingSize == 0) {
|
||||
if (MMC1_romSelectionReg0 == 1) {
|
||||
baseBank = 16;
|
||||
}
|
||||
} else {
|
||||
baseBank =
|
||||
(MMC1_romSelectionReg0 | (MMC1_romSelectionReg1 << 1)) << 3;
|
||||
}
|
||||
} else if (numPRGROM >= 16) {
|
||||
// 512 kB cart
|
||||
if (MMC1_romSelectionReg0 == 1) {
|
||||
baseBank = 8;
|
||||
}
|
||||
}
|
||||
if (MMC1_prgSwitchingSize == 0) {
|
||||
// 32kB
|
||||
bank = baseBank + (value & 0xf);
|
||||
MMC1_load32kRomBank(bank, 0x8000);
|
||||
} else {
|
||||
// 16kB
|
||||
bank = baseBank * 2 + (value & 0xf);
|
||||
if (MMC1_prgSwitchingArea == 0) {
|
||||
MMC1_loadRomBank(bank, 0xc000);
|
||||
} else {
|
||||
MMC1_loadRomBank(bank, 0x8000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 MMC1_Write(U16 address, U8 value)
|
||||
{
|
||||
// See what should be done with the written value:
|
||||
if ((value & 128) != 0) {
|
||||
// Reset buffering:
|
||||
MMC1_regBufferCounter = 0;
|
||||
MMC1_regBuffer = 0;
|
||||
// Reset register:
|
||||
if (MMC1_getRegNumber(address) == 0) {
|
||||
MMC1_prgSwitchingArea = 1;
|
||||
MMC1_prgSwitchingSize = 1;
|
||||
}
|
||||
} else {
|
||||
// Continue buffering:
|
||||
//regBuffer = (regBuffer & (0xFF-(1<<regBufferCounter))) | ((value & (1<<regBufferCounter))<<regBufferCounter);
|
||||
MMC1_regBuffer =
|
||||
(MMC1_regBuffer & (0xff - (1 << MMC1_regBufferCounter))) |
|
||||
((value & 1) << MMC1_regBufferCounter);
|
||||
MMC1_regBufferCounter++;
|
||||
if (MMC1_regBufferCounter == 5) {
|
||||
// Use the buffered value:
|
||||
MMC1_setReg(MMC1_getRegNumber(address), MMC1_regBuffer);
|
||||
// Reset buffer:
|
||||
MMC1_regBuffer = 0;
|
||||
MMC1_regBufferCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mapper #2 [UNROM]
|
||||
|
||||
U0 UNROM_Write(U16 address, U8 value)
|
||||
{
|
||||
// Swap in the given PRG-ROM bank:
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10+0x4000*(value), 0x4000);
|
||||
}
|
||||
|
||||
|
||||
// Mapper #3 [CNROM]
|
||||
|
||||
U0 CNROM_Write(U16 address, U8 value)
|
||||
{
|
||||
I64 bank = value & 3;
|
||||
//Copy the ROM into the PPU's memory
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+(0x4000*numPRGROM)+(0x2000*(bank)), 0x2000);
|
||||
}
|
||||
|
||||
// Mapper #4 [MMC3]
|
||||
|
||||
#define MMC3_CMD_SEL_2_1K_VROM_0000 0
|
||||
#define MMC3_CMD_SEL_2_1K_VROM_0800 1
|
||||
#define MMC3_CMD_SEL_1K_VROM_1000 2
|
||||
#define MMC3_CMD_SEL_1K_VROM_1400 3
|
||||
#define MMC3_CMD_SEL_1K_VROM_1800 4
|
||||
#define MMC3_CMD_SEL_1K_VROM_1C00 5
|
||||
#define MMC3_CMD_SEL_ROM_PAGE1 6
|
||||
#define MMC3_CMD_SEL_ROM_PAGE2 7
|
||||
|
||||
I64 MMC3_command = NULL;
|
||||
I64 MMC3_prgAddressSelect = NULL;
|
||||
I64 MMC3_chrAddressSelect = NULL;
|
||||
I64 MMC3_pageNumber = NULL;
|
||||
I64 MMC3_irqCounter = NULL;
|
||||
I64 MMC3_irqLatchValue = NULL;
|
||||
I64 MMC3_irqEnable = NULL;
|
||||
I64 MMC3_prgAddressChanged = FALSE;
|
||||
|
||||
U0 MMC3_executeCommand(I64 cmd, I64 arg) {
|
||||
switch (cmd)
|
||||
{
|
||||
case MMC3_CMD_SEL_2_1K_VROM_0000:
|
||||
// Select 2 1KB VROM pages at 0x0000:
|
||||
if (MMC3_chrAddressSelect == 0) {
|
||||
MMC1_load1kVromBank(arg, 0x0000);
|
||||
MMC1_load1kVromBank(arg + 1, 0x0400);
|
||||
} else {
|
||||
MMC1_load1kVromBank(arg, 0x1000);
|
||||
MMC1_load1kVromBank(arg + 1, 0x1400);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_2_1K_VROM_0800:
|
||||
// Select 2 1KB VROM pages at 0x0800:
|
||||
if (MMC3_chrAddressSelect == 0) {
|
||||
MMC1_load1kVromBank(arg, 0x0800);
|
||||
MMC1_load1kVromBank(arg + 1, 0x0c00);
|
||||
} else {
|
||||
MMC1_load1kVromBank(arg, 0x1800);
|
||||
MMC1_load1kVromBank(arg + 1, 0x1c00);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_1K_VROM_1000:
|
||||
// Select 1K VROM Page at 0x1000:
|
||||
if (MMC3_chrAddressSelect == 0) {
|
||||
MMC1_load1kVromBank(arg, 0x1000);
|
||||
} else {
|
||||
MMC1_load1kVromBank(arg, 0x0000);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_1K_VROM_1400:
|
||||
// Select 1K VROM Page at 0x1400:
|
||||
if (MMC3_chrAddressSelect == 0) {
|
||||
MMC1_load1kVromBank(arg, 0x1400);
|
||||
} else {
|
||||
MMC1_load1kVromBank(arg, 0x0400);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_1K_VROM_1800:
|
||||
// Select 1K VROM Page at 0x1800:
|
||||
if (MMC3_chrAddressSelect == 0) {
|
||||
MMC1_load1kVromBank(arg, 0x1800);
|
||||
} else {
|
||||
MMC1_load1kVromBank(arg, 0x0800);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_1K_VROM_1C00:
|
||||
// Select 1K VROM Page at 0x1C00:
|
||||
if (MMC3_chrAddressSelect == 0) {
|
||||
MMC1_load1kVromBank(arg, 0x1c00);
|
||||
} else {
|
||||
MMC1_load1kVromBank(arg, 0x0c00);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_ROM_PAGE1:
|
||||
if (MMC3_prgAddressChanged) {
|
||||
// Load the two hardwired banks:
|
||||
if (MMC3_prgAddressSelect == 0) {
|
||||
MMC1_load8kRomBank((numPRGROM - 1) * 2, 0xc000);
|
||||
} else {
|
||||
MMC1_load8kRomBank((numPRGROM - 1) * 2, 0x8000);
|
||||
}
|
||||
MMC3_prgAddressChanged = FALSE;
|
||||
}
|
||||
|
||||
// Select first switchable ROM page:
|
||||
if (MMC3_prgAddressSelect == 0) {
|
||||
MMC1_load8kRomBank(arg, 0x8000);
|
||||
} else {
|
||||
MMC1_load8kRomBank(arg, 0xc000);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC3_CMD_SEL_ROM_PAGE2:
|
||||
// Select second switchable ROM page:
|
||||
MMC1_load8kRomBank(arg, 0xa000);
|
||||
|
||||
// hardwire appropriate bank:
|
||||
if (MMC3_prgAddressChanged) {
|
||||
// Load the two hardwired banks:
|
||||
if (MMC3_prgAddressSelect == 0) {
|
||||
MMC1_load8kRomBank((numPRGROM - 1) * 2, 0xc000);
|
||||
} else {
|
||||
MMC1_load8kRomBank((numPRGROM - 1) * 2, 0x8000);
|
||||
}
|
||||
MMC3_prgAddressChanged = FALSE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
U0 MMC3_Write(U16 address, U8 value)
|
||||
{
|
||||
switch (address)
|
||||
{
|
||||
case 0x8000:
|
||||
// Command/Address Select register
|
||||
MMC3_command = value & 7;
|
||||
I64 tmp = (value >> 6) & 1;
|
||||
if (tmp != MMC3_prgAddressSelect) {
|
||||
MMC3_prgAddressChanged = TRUE;
|
||||
}
|
||||
MMC3_prgAddressSelect = tmp;
|
||||
MMC3_chrAddressSelect = (value >> 7) & 1;
|
||||
break;
|
||||
|
||||
case 0x8001:
|
||||
// Page number for command
|
||||
MMC3_executeCommand(MMC3_command, value);
|
||||
break;
|
||||
|
||||
case 0xa000:
|
||||
// Mirroring select
|
||||
if ((value & 1) != 0) {
|
||||
mirroringType = MIRR_HORZ;
|
||||
} else {
|
||||
mirroringType = MIRR_VERT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa001:
|
||||
// SaveRAM Toggle
|
||||
// TODO
|
||||
//nes.getRom().setSaveState((value&1)!=0);
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
// IRQ Counter register
|
||||
MMC3_irqCounter = value;
|
||||
//nes.ppu.mapperIrqCounter = 0;
|
||||
break;
|
||||
|
||||
case 0xc001:
|
||||
// IRQ Latch register
|
||||
MMC3_irqLatchValue = value;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
// IRQ Control Reg 0 (disable)
|
||||
//irqCounter = irqLatchValue;
|
||||
MMC3_irqEnable = 0;
|
||||
break;
|
||||
|
||||
case 0xe001:
|
||||
// IRQ Control Reg 1 (enable)
|
||||
MMC3_irqEnable = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Not a MMC3 register.
|
||||
// The game has probably crashed,
|
||||
// since it tries to write to ROM..
|
||||
// IGNORE.
|
||||
}
|
||||
}
|
||||
|
||||
U0 MMC3_clockIrqCounter()
|
||||
{
|
||||
if (MMC3_irqEnable == 1) {
|
||||
MMC3_irqCounter--;
|
||||
if (MMC3_irqCounter < 0)
|
||||
{
|
||||
// Trigger IRQ:
|
||||
mapper_request_irq=TRUE;
|
||||
MMC3_irqCounter = MMC3_irqLatchValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mapper #11 [Color Dreams]
|
||||
|
||||
U0 ColorDreams_Write(U16 address, U8 value)
|
||||
{
|
||||
// Swap in the given PRG-ROM bank:
|
||||
I64 prgbank = ((value & 0xf) * 2) % numPRGROM;
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10+0x4000*(prgbank), 0x8000);
|
||||
if (numCHRROM > 0) {
|
||||
// Swap in the given VROM bank at 0x0000:
|
||||
I64 bank = ((value >> 4) * 2);
|
||||
MemCpy(MMU.VRAM, cartridgebuffer+0x10+(0x4000*numPRGROM)+(0x1000*(bank)), 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
// Mapper #17 [FFE Copier]
|
||||
U0 FFE_Write(U16 address, U8 value)
|
||||
{
|
||||
switch (address)
|
||||
{
|
||||
case 0x4500://Config register
|
||||
break;
|
||||
case 0x4501://Disable IRQ
|
||||
break;
|
||||
case 0x4502://IRQ Counter low byte
|
||||
break;
|
||||
case 0x4503://IRQ Counter high byte
|
||||
break;
|
||||
case 0x4504...0x4507://Switch PRG bank
|
||||
I64 prgbank = address-0x4504;
|
||||
MemCpy(MMU.RAM+0x8000+(prgbank*0x2000), cartridgebuffer+0x10+0x2000*(prgbank), 0x2000);
|
||||
break;
|
||||
case 0x4510...0x451B://Switch CHR bank
|
||||
I64 chrbank = address-0x4510;
|
||||
MemCpy(MMU.VRAM+(chrbank*0x400), cartridgebuffer+0x10+(0x4000*numPRGROM)+(chrbank*0x400), 0x400);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Mapper #18 [Jaleco SS88006]
|
||||
|
||||
U8 SS88006_lo = 0;
|
||||
Bool SS88006_loWrite = FALSE;
|
||||
U8 SS88006_hi = 0;
|
||||
Bool SS88006_hiWrite = FALSE;
|
||||
|
||||
U8 SS88006_irqctr;
|
||||
|
||||
U0 SS88006_Write(U16 address, U8 value)
|
||||
{
|
||||
I64 bank;
|
||||
if (address & 1)
|
||||
{
|
||||
SS88006_hi = value << 4;
|
||||
SS88006_hiWrite = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SS88006_lo = value;
|
||||
SS88006_loWrite = TRUE;
|
||||
}
|
||||
if (SS88006_loWrite && SS88006_hiWrite)
|
||||
{
|
||||
bank = SS88006_lo + SS88006_hi;
|
||||
switch (address)
|
||||
{
|
||||
case 0x8000...0x8001:
|
||||
MemCpy(MMU.RAM+0x8000, cartridgebuffer+0x10+0x2000*(bank), 0x2000);
|
||||
break;
|
||||
case 0x8002...0x8003:
|
||||
MemCpy(MMU.RAM+0xA000, cartridgebuffer+0x10+0x2000*(bank), 0x2000);
|
||||
break;
|
||||
case 0x9000...0x9001:
|
||||
MemCpy(MMU.RAM+0xC000, cartridgebuffer+0x10+0x2000*(bank), 0x2000);
|
||||
break;
|
||||
case 0xA000...0xA001:
|
||||
MemCpy(MMU.VRAM+0x0000, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xA002...0xA003:
|
||||
MemCpy(MMU.VRAM+0x0400, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xB000...0xB001:
|
||||
MemCpy(MMU.VRAM+0x0800, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xB002...0xB003:
|
||||
MemCpy(MMU.VRAM+0x0C00, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xC000...0xC001:
|
||||
MemCpy(MMU.VRAM+0x1000, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xC002...0xC003:
|
||||
MemCpy(MMU.VRAM+0x1400, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xD000...0xD001:
|
||||
MemCpy(MMU.VRAM+0x1800, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
case 0xD002...0xD003:
|
||||
MemCpy(MMU.VRAM+0x1C00, cartridgebuffer+0x10+(0x4000*numPRGROM)+(bank*0x400), 0x400);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SS88006_loWrite = FALSE;
|
||||
SS88006_hiWrite = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
#define FRAME_RATE 60
|
||||
|
||||
U32 pixelWidth = 2;
|
||||
U32 pixelHeight = 2;
|
||||
U32 ppu_colors[64] =
|
||||
@@ -56,20 +54,19 @@ U0 verinc() {
|
||||
}
|
||||
}
|
||||
|
||||
U0 setPixelColor(I64 x, I64 y, I64 color) {
|
||||
U8 *pixel=TG_Canvas->body;
|
||||
U0 setPixelColor(I64 x, I64 y, I64 color, CDC *dc=gameCanvas) {
|
||||
I64 dx = 0, dy=0;
|
||||
for(dx=0; dx<pixelWidth; ++dx) {
|
||||
for(dy=0; dy<pixelHeight; ++dy) {
|
||||
if (fit_screen)
|
||||
{
|
||||
gameCanvas->color = 16+color.u8[0];
|
||||
GrPlot(gameCanvas, x+32, y);
|
||||
dc->color = 16+color.u8[0];
|
||||
GrPlot(dc, x+32, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameCanvas->color = 16+color.u8[0];
|
||||
GrPlot(gameCanvas, x+32, y-24);
|
||||
dc->color = 16+color.u8[0];
|
||||
GrPlot(dc, x+32, y-24);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,6 +87,21 @@ I64 getActiveSpriteIndex(PPU2C02state *state) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
I64 getActiveSpriteIndex16(PPU2C02state *state) {
|
||||
U8 i;
|
||||
for(i=0; i<state->num_sprites; ++i) {
|
||||
if( state->sprites[i].x == 0 && state->sprites[i].shifts_remaining > 0 ) {
|
||||
U8 bit_0 = (state->sprites[i].shift_register_2 & (1 << 7)) >> 7;
|
||||
U8 bit_1 = (state->sprites[i].shift_register_3 & (1 << 7)) >> 7;
|
||||
U8 bg_color_index = (bit_1 << 1) | bit_0;
|
||||
if( bg_color_index > 0 ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************
|
||||
* fetching values
|
||||
******************/
|
||||
@@ -130,6 +142,18 @@ U0 renderPixel(PPU2C02state *state) {
|
||||
bit_1 = (state->AT_shift_1 & (1 << shift)) >> shift;
|
||||
U8 bg_at_index = (bit_1 << 1) | bit_0;
|
||||
|
||||
U16 palette_base;
|
||||
U8 color_value;
|
||||
U32 color;
|
||||
|
||||
I64 ofs = 0;
|
||||
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{
|
||||
ofs = 8;
|
||||
}
|
||||
|
||||
//8x8
|
||||
//get sprite color index and active sprite
|
||||
U8 sprite_color_index = 0;
|
||||
I64 active_sprite_index = getActiveSpriteIndex(state);
|
||||
@@ -139,27 +163,19 @@ U0 renderPixel(PPU2C02state *state) {
|
||||
sprite_color_index = (bit_1 << 1) | bit_0;
|
||||
}
|
||||
|
||||
U16 palette_base;
|
||||
U8 color_value;
|
||||
U32 color;
|
||||
|
||||
//draw the pixel on the screen, depending on color and priority
|
||||
if( bg_color_index == 0 && sprite_color_index == 0 ) {
|
||||
//setPixelColor(state->dot, state->scanline, ppu_colors[MMU.VRAM[0x3F00]]);
|
||||
setPixelColor(state->dot, state->scanline, MMU.VRAM[0x3F00]);
|
||||
}
|
||||
else if( (sprite_color_index != 0 && bg_color_index == 0) ||
|
||||
(sprite_color_index != 0 && bg_color_index != 0 && (state->sprites[active_sprite_index].byte2 & (1<<5)) == 0) ) {
|
||||
//assert( active_sprite_index != -1 );
|
||||
palette_base = getSpritePaletteBase(state->sprites[active_sprite_index].attribute);
|
||||
color_value = readVRAM(palette_base + sprite_color_index);
|
||||
//color = ppu_colors[color_value];
|
||||
setPixelColor(state->dot, state->scanline, color_value);
|
||||
}
|
||||
else {
|
||||
palette_base = getBackgroundPaletteBase(bg_at_index);
|
||||
color_value = readVRAM(palette_base + bg_color_index);
|
||||
//color = ppu_colors[color_value];
|
||||
setPixelColor(state->dot, state->scanline, color_value);
|
||||
}
|
||||
|
||||
@@ -167,6 +183,30 @@ U0 renderPixel(PPU2C02state *state) {
|
||||
if( active_sprite_index != -1 && state->sprites[active_sprite_index].sprite_index == 0 && sprite_color_index != 0 && bg_color_index == 0 ) {
|
||||
state->sprite_zero_hit = 1;
|
||||
}
|
||||
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{ //8x16
|
||||
sprite_color_index = 0;
|
||||
active_sprite_index = getActiveSpriteIndex16(state);
|
||||
if( active_sprite_index != -1 )
|
||||
{
|
||||
bit_0 = (state->sprites[active_sprite_index].shift_register_2 & (1 << 7)) >> 7;
|
||||
bit_1 = (state->sprites[active_sprite_index].shift_register_3 & (1 << 7)) >> 7;
|
||||
sprite_color_index = (bit_1 << 1) | bit_0;
|
||||
}
|
||||
if (sprite_color_index)
|
||||
{
|
||||
palette_base = getSpritePaletteBase(state->sprites[active_sprite_index].attribute);
|
||||
color_value = readVRAM(palette_base + sprite_color_index);
|
||||
setPixelColor(state->dot, state->scanline, color_value, Canvas16);
|
||||
}
|
||||
}
|
||||
|
||||
//handle sprite zero hit
|
||||
if( active_sprite_index != -1 && state->sprites[active_sprite_index].sprite_index == 0 && sprite_color_index != 0 && bg_color_index == 0 ) {
|
||||
state->sprite_zero_hit = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************
|
||||
@@ -179,39 +219,90 @@ U0 loadScanlineSprites(PPU2C02state *state) {
|
||||
for(i=0; i<8; ++i) {
|
||||
state->sprites[i].shift_register_0 = 0;
|
||||
state->sprites[i].shift_register_1 = 0;
|
||||
state->sprites[i].shift_register_2 = 0;
|
||||
state->sprites[i].shift_register_3 = 0;
|
||||
}
|
||||
|
||||
for(i=0x00; i<0xFF; i+=4) {
|
||||
//assert( (MMU.RAM[0x2000] & (1 << 5)) == 0 ); //only allow 8x8 sprites
|
||||
|
||||
U8 y = readSPRRAM(i+0)+1;
|
||||
U8 pattern_index = readSPRRAM(i+1);
|
||||
U8 byte2 = readSPRRAM(i+2);
|
||||
U8 x = readSPRRAM(i+3);
|
||||
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{
|
||||
y += 8;
|
||||
}
|
||||
|
||||
if( y <= state->scanline && y+8 > state->scanline ) {
|
||||
|
||||
U16 pattern_base = 0x0000;
|
||||
if( (MMU.RAM[0x2000] & (1 << 3)) ) {
|
||||
pattern_base = 0x1000;
|
||||
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{ //8x16
|
||||
if( (pattern_index & 1) ) {
|
||||
pattern_base = 0x1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern_base += 16;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //8x8
|
||||
if( (MMU.RAM[0x2000] & (1 << 3)) ) {
|
||||
pattern_base = 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
U16 palette_base = getSpritePaletteBase(byte2 & 3);
|
||||
|
||||
U8 pattern_0;
|
||||
U8 pattern_1;
|
||||
U8 pattern_2;
|
||||
U8 pattern_3;
|
||||
|
||||
I64 row = state->scanline-y;
|
||||
U8 pattern_0 = MMU.VRAM[pattern_base + (pattern_index*16+row)];
|
||||
U8 pattern_1 = MMU.VRAM[pattern_base + (pattern_index*16+row+8)];
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{
|
||||
pattern_0 = readVRAM(pattern_base + (pattern_index*16+row));
|
||||
pattern_1 = readVRAM(pattern_base + (pattern_index*16+row+8));
|
||||
pattern_2 = readVRAM(pattern_base + (pattern_index*16+row-16));
|
||||
pattern_3 = readVRAM(pattern_base + (pattern_index*16+row-8));
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern_0 = readVRAM(pattern_base + (pattern_index*16+row));
|
||||
pattern_1 = readVRAM(pattern_base + (pattern_index*16+row+8));
|
||||
pattern_2 = readVRAM(pattern_base + (pattern_index*16+row-16));
|
||||
pattern_3 = readVRAM(pattern_base + (pattern_index*16+row-8));
|
||||
}
|
||||
|
||||
//flip y
|
||||
if( byte2 & (1 << 7) ) {
|
||||
pattern_0 = MMU.VRAM[pattern_base + (pattern_index*16+(7-row))];
|
||||
pattern_1 = MMU.VRAM[pattern_base + (pattern_index*16+(7-row)+8)];
|
||||
if (MMU.RAM[0x2000] & (1 << 5) != 0)
|
||||
{
|
||||
pattern_2 = readVRAM(pattern_base + (pattern_index*16+(7-row)));
|
||||
pattern_3 = readVRAM(pattern_base + (pattern_index*16+(7-row)+8));
|
||||
pattern_0 = readVRAM(pattern_base + (pattern_index*16+(7-row)-16));
|
||||
pattern_1 = readVRAM(pattern_base + (pattern_index*16+(7-row)-8));
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern_0 = readVRAM(pattern_base + (pattern_index*16+(7-row)));
|
||||
pattern_1 = readVRAM(pattern_base + (pattern_index*16+(7-row)+8));
|
||||
pattern_2 = readVRAM(pattern_base + (pattern_index*16+(7-row)-16));
|
||||
pattern_3 = readVRAM(pattern_base + (pattern_index*16+(7-row)-8));
|
||||
}
|
||||
}
|
||||
|
||||
//flip x, reverse the bits in the patterns
|
||||
if(byte2 & (1 << 6) ) {
|
||||
U8 new_pattern_0 = 0;
|
||||
U8 new_pattern_1 = 0;
|
||||
U8 new_pattern_2 = 0;
|
||||
U8 new_pattern_3 = 0;
|
||||
I64 bit;
|
||||
for(bit=0; bit<8; ++bit) {
|
||||
new_pattern_0 <<= 1;
|
||||
@@ -220,9 +311,17 @@ U0 loadScanlineSprites(PPU2C02state *state) {
|
||||
new_pattern_1 <<= 1;
|
||||
new_pattern_1 |= (pattern_1&1);
|
||||
pattern_1 >>= 1;
|
||||
new_pattern_2 <<= 1;
|
||||
new_pattern_2 |= (pattern_2&1);
|
||||
pattern_2 >>= 1;
|
||||
new_pattern_3 <<= 1;
|
||||
new_pattern_3 |= (pattern_3&1);
|
||||
pattern_3 >>= 1;
|
||||
}
|
||||
pattern_0 = new_pattern_0;
|
||||
pattern_1 = new_pattern_1;
|
||||
pattern_2 = new_pattern_2;
|
||||
pattern_3 = new_pattern_3;
|
||||
}
|
||||
|
||||
state->sprites[state->num_sprites].sprite_index = i;
|
||||
@@ -230,6 +329,8 @@ U0 loadScanlineSprites(PPU2C02state *state) {
|
||||
state->sprites[state->num_sprites].attribute = (byte2 & 3);
|
||||
state->sprites[state->num_sprites].shift_register_0 = pattern_0;
|
||||
state->sprites[state->num_sprites].shift_register_1 = pattern_1;
|
||||
state->sprites[state->num_sprites].shift_register_2 = pattern_2;
|
||||
state->sprites[state->num_sprites].shift_register_3 = pattern_3;
|
||||
state->sprites[state->num_sprites].shifts_remaining = 8;
|
||||
state->sprites[state->num_sprites].byte2 = byte2;
|
||||
|
||||
@@ -248,16 +349,28 @@ U0 updatePPUrenderingData(PPU2C02state *state) {
|
||||
state->bitmap_shift_0 &= ~1;
|
||||
state->bitmap_shift_1 &= ~1;
|
||||
|
||||
state->bitmap_shift_2 <<= 1;
|
||||
state->bitmap_shift_3 <<= 1;
|
||||
state->bitmap_shift_2 &= ~1;
|
||||
state->bitmap_shift_3 &= ~1;
|
||||
|
||||
state->AT_shift_0 <<= 1;
|
||||
state->AT_shift_1 <<= 1;
|
||||
state->AT_shift_0 &= ~1;
|
||||
state->AT_shift_1 &= ~1;
|
||||
|
||||
state->AT_shift_2 <<= 1;
|
||||
state->AT_shift_3 <<= 1;
|
||||
state->AT_shift_2 &= ~1;
|
||||
state->AT_shift_3 &= ~1;
|
||||
|
||||
I64 i;
|
||||
for(i=0; i<state->num_sprites; ++i) {
|
||||
if( state->sprites[i].x == 0 && state->sprites[i].shifts_remaining > 0) {
|
||||
state->sprites[i].shift_register_0 <<= 1;
|
||||
state->sprites[i].shift_register_1 <<= 1;
|
||||
state->sprites[i].shift_register_2 <<= 1;
|
||||
state->sprites[i].shift_register_3 <<= 1;
|
||||
state->sprites[i].shifts_remaining -= 1;
|
||||
}
|
||||
else {
|
||||
@@ -306,15 +419,19 @@ U0 fetchAttribute(PPU2C02state *state) {
|
||||
U8 at = getAttributeTableValue(attribute_address, (MMU.VRAM_address & 0x001F)*8, ((MMU.VRAM_address & (0x001F << 5)) >> 5)*8);
|
||||
if(at & 1) {
|
||||
state->AT_shift_0_latch = 0xFF;
|
||||
state->AT_shift_2_latch = 0xFF;
|
||||
}
|
||||
else {
|
||||
state->AT_shift_0_latch = 0x00;
|
||||
state->AT_shift_2_latch = 0x00;
|
||||
}
|
||||
if(at & 2) {
|
||||
state->AT_shift_1_latch = 0xFF;
|
||||
state->AT_shift_3_latch = 0xFF;
|
||||
}
|
||||
else {
|
||||
state->AT_shift_1_latch = 0x00;
|
||||
state->AT_shift_3_latch = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +451,7 @@ U0 handleVisibleScanline(PPU2C02state *state) {
|
||||
loadScanlineSprites(state);
|
||||
return;
|
||||
}
|
||||
if( !rendering_enabled() ) {
|
||||
if( !rendering_enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,7 +464,9 @@ U0 handleVisibleScanline(PPU2C02state *state) {
|
||||
if( MMU.RAM[0x2000] & (1 << 4) ) {
|
||||
pattern_base = 0x1000;
|
||||
}
|
||||
U16 pattern_index = MMU.VRAM[state->nametable_base];
|
||||
|
||||
U16 pattern_index = readVRAM(state->nametable_base);
|
||||
|
||||
U8 row = ((MMU.VRAM_address&0x7000) >> 12);
|
||||
|
||||
if( state->dot < 256 || (state->dot > 320 && state->dot <= 336) ) {
|
||||
@@ -357,9 +476,13 @@ U0 handleVisibleScanline(PPU2C02state *state) {
|
||||
case 0:
|
||||
state->bitmap_shift_0 |= state->bitmap_shift_0_latch;
|
||||
state->bitmap_shift_1 |= state->bitmap_shift_1_latch;
|
||||
state->bitmap_shift_2 |= state->bitmap_shift_2_latch;
|
||||
state->bitmap_shift_3 |= state->bitmap_shift_3_latch;
|
||||
|
||||
state->AT_shift_0 |= state->AT_shift_0_latch;
|
||||
state->AT_shift_1 |= state->AT_shift_1_latch;
|
||||
state->AT_shift_2 |= state->AT_shift_2_latch;
|
||||
state->AT_shift_3 |= state->AT_shift_3_latch;
|
||||
|
||||
horinc();
|
||||
break;
|
||||
@@ -370,13 +493,14 @@ U0 handleVisibleScanline(PPU2C02state *state) {
|
||||
fetchAttribute(state);
|
||||
break;
|
||||
case 5:
|
||||
state->bitmap_shift_0_latch = MMU.VRAM[pattern_base + pattern_index*16+row];
|
||||
state->bitmap_shift_0_latch = readVRAM(pattern_base + pattern_index*16+row);
|
||||
state->bitmap_shift_2_latch = readVRAM(pattern_base + pattern_index*16+row-16);
|
||||
break;
|
||||
case 7:
|
||||
state->bitmap_shift_1_latch = MMU.VRAM[pattern_base + pattern_index*16+row+8];
|
||||
state->bitmap_shift_1_latch = readVRAM(pattern_base + pattern_index*16+row+8);
|
||||
state->bitmap_shift_3_latch = readVRAM(pattern_base + pattern_index*16+row-8);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( state->dot == 256 ) {
|
||||
@@ -395,7 +519,6 @@ U8 PPUcycle(PPU2C02state *state) {
|
||||
|
||||
if( state->nmi_output && state->nmi_occurred ) {
|
||||
state->nmi_occurred = 0;
|
||||
//NMI(&CPU_state);
|
||||
nmi6502;
|
||||
}
|
||||
|
||||
@@ -404,15 +527,28 @@ U8 PPUcycle(PPU2C02state *state) {
|
||||
if(state->dot == 341) {
|
||||
state->scanline += 1;
|
||||
state->dot = 0;
|
||||
if (mapper == 18)
|
||||
{
|
||||
SS88006_irqctr--;
|
||||
if (!SS88006_irqctr)
|
||||
{
|
||||
irq6502;
|
||||
}
|
||||
}
|
||||
}
|
||||
state->scanline %= 262;
|
||||
//skip first cycle on odd frames
|
||||
if(state->scanline == 0 && state->dot == 0 && state->odd_frame == 1 && rendering_enabled()) {
|
||||
if(state->scanline == 0 && state->dot == 0 && state->odd_frame == 1 && rendering_enabled) {
|
||||
state->dot = 1;
|
||||
}
|
||||
|
||||
if ( state->scanline == 20 && state->dot == 0 && rendering_enabled && mapper == 4)
|
||||
{
|
||||
MMC3_clockIrqCounter;
|
||||
}
|
||||
|
||||
//visible scanlines
|
||||
if( state->scanline < 240 && rendering_enabled() ) {
|
||||
if( state->scanline < 240 && rendering_enabled ) {
|
||||
handleVisibleScanline(state);
|
||||
|
||||
//visible cycles
|
||||
@@ -441,7 +577,7 @@ U8 PPUcycle(PPU2C02state *state) {
|
||||
state->nmi_occurred = 0;
|
||||
}
|
||||
|
||||
else if(state->dot >= 280 && state->dot <= 304 && rendering_enabled()) {
|
||||
else if(state->dot >= 280 && state->dot <= 304 && rendering_enabled) {
|
||||
//v: IHGF.ED CBA..... = t: IHGF.ED CBA.....
|
||||
MMU.VRAM_address &= 1055; //1055 = 0000010000011111b
|
||||
MMU.VRAM_address |= (MMU.t & ~1055 & ~(1<<15) );
|
||||
@@ -449,5 +585,4 @@ U8 PPUcycle(PPU2C02state *state) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
Regular → Executable
@@ -1,7 +1,7 @@
|
||||
# templenes
|
||||
NES Emulator for TempleOS
|
||||
|
||||
This is a work in progress. Currently, only Mapper #0 games work, and things are buggy. Tested on bare-metal and VirtualBox 6.0, YMMV.
|
||||
This is a work in progress, and things are buggy. Tested on bare-metal and VirtualBox 6.0, YMMV.
|
||||
|
||||
The emulator runs in 320x200 256 color video mode. Since NES display resolution exceeds these boundaries, there is an option to view 1:1 (topmost pixels not visible) or Scale2Fit, which scales the image to the 320x200 viewport, albeit with loss of quality.
|
||||
|
||||
@@ -19,10 +19,8 @@ PPU/MMU is a modified version of [NESlig](https://github.com/toblu302/NESlig) co
|
||||
|
||||
# TODO
|
||||
|
||||
- Mappers
|
||||
|
||||
- Sound
|
||||
- More mappers
|
||||
|
||||
- GUI Dialog boxes and other menu options
|
||||
|
||||
- Everything else
|
||||
- Everything else
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// vim: set ft=c:
|
||||
|
||||
#include "Load";
|
||||
|
||||
//TempleNES("some_rom_file.nes");
|
||||
|
||||
Regular → Executable
Reference in New Issue
Block a user