From e116014742f122fb70305ffcb6de49d8fa0dbd37 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 31 Dec 2014 14:13:36 -0800 Subject: [PATCH 001/121] First pass of NTSC integration --- ApplewinExpress10.00.vcxproj | 2 + source/Applewin.cpp | 3 +- source/CPU.cpp | 33 ++++--- source/CPU/cpu6502.h | 13 +++ source/CPU/cpu65C02.h | 13 +++ source/CPU/cpu65d02.h | 13 +++ source/Configuration/PageConfig.cpp | 2 +- source/Frame.h | 7 ++ source/SaveState.cpp | 5 + source/StdAfx.h | 1 + source/Video.cpp | 144 ++++++++++++++++------------ source/Video.h | 61 +++++++----- 12 files changed, 191 insertions(+), 106 deletions(-) diff --git a/ApplewinExpress10.00.vcxproj b/ApplewinExpress10.00.vcxproj index e6fadecf..48c2bca6 100644 --- a/ApplewinExpress10.00.vcxproj +++ b/ApplewinExpress10.00.vcxproj @@ -265,6 +265,7 @@ + Create Create @@ -392,6 +393,7 @@ + diff --git a/source/Applewin.cpp b/source/Applewin.cpp index a4d5ee05..6e80f7cd 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -51,6 +51,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Speech.h" #endif #include "Video.h" +#include "NTSC.h" #include "Configuration\About.h" #include "Configuration\PropertySheet.h" @@ -408,7 +409,7 @@ void LoadConfiguration(void) case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. } - // + NTSC_VideoInitAppleType(); if (!REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &joytype[JN_JOYSTICK0])) LoadConfigOldJoystick(JN_JOYSTICK0); diff --git a/source/CPU.cpp b/source/CPU.cpp index fadaecbb..faf45fbf 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -96,6 +96,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Speech.h" #endif #include "Video.h" +#include "NTSC.h" #include "z80emu.h" #include "Z80VICE\z80.h" @@ -103,25 +104,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debugger\Debug.h" - -#define AF_SIGN 0x80 -#define AF_OVERFLOW 0x40 -#define AF_RESERVED 0x20 -#define AF_BREAK 0x10 -#define AF_DECIMAL 0x08 -#define AF_INTERRUPT 0x04 -#define AF_ZERO 0x02 -#define AF_CARRY 0x01 +// 6502 Accumulator Bit Flags + #define AF_SIGN 0x80 + #define AF_OVERFLOW 0x40 + #define AF_RESERVED 0x20 + #define AF_BREAK 0x10 + #define AF_DECIMAL 0x08 + #define AF_INTERRUPT 0x04 + #define AF_ZERO 0x02 + #define AF_CARRY 0x01 #define SHORTOPCODES 22 #define BENCHOPCODES 33 -// What is this 6502 code? -static BYTE benchopcode[BENCHOPCODES] = {0x06,0x16,0x24,0x45,0x48,0x65,0x68,0x76, - 0x84,0x85,0x86,0x91,0x94,0xA4,0xA5,0xA6, - 0xB1,0xB4,0xC0,0xC4,0xC5,0xE6, - 0x19,0x6D,0x8D,0x99,0x9D,0xAD,0xB9,0xBD, - 0xDD,0xED,0xEE}; +// What is this 6502 code? Compressed 6502 code -- see: CpuSetupBenchmark() +static BYTE benchopcode[BENCHOPCODES] = { + 0x06,0x16,0x24,0x45,0x48,0x65,0x68,0x76, + 0x84,0x85,0x86,0x91,0x94,0xA4,0xA5,0xA6, + 0xB1,0xB4,0xC0,0xC4,0xC5,0xE6, + 0x19,0x6D,0x8D,0x99,0x9D,0xAD,0xB9,0xBD, + 0xDD,0xED,0xEE +}; regsrec regs; unsigned __int64 g_nCumulativeCycles = 0; diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index eb140bac..a22aa764 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -44,6 +44,11 @@ static DWORD Cpu6502 (DWORD uTotalCycles) UINT uExtraCycles = 0; BYTE iOpcode; +// NTSC_BEGIN + ULONG uElapsedCycles; + ULONG uPreviousCycles = uExecutedCycles; +// NTSC_END + if (g_ActiveCPU == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) @@ -315,6 +320,14 @@ static DWORD Cpu6502 (DWORD uTotalCycles) } } +// NTSC_BEGIN + uElapsedCycles = uExecutedCycles - uPreviousCycles; + if( g_bFullSpeed ) + NTSC_VideoUpdateCycles( uElapsedCycles ); + else + g_pNTSC_FuncVideoUpdate( uElapsedCycles ); +// NTSC_END + CheckInterruptSources(uExecutedCycles); NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz); IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz); diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index 43223ef9..6a9c30f3 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -47,6 +47,11 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) UINT uExtraCycles = 0; BYTE iOpcode; +// NTSC_BEGIN + ULONG uElapsedCycles; + ULONG uPreviousCycles = uExecutedCycles; +// NTSC_END + if (g_ActiveCPU == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) @@ -319,6 +324,14 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) #undef $ } +// NTSC_BEGIN + uElapsedCycles = uExecutedCycles - uPreviousCycles; + if( g_bFullSpeed ) + NTSC_VideoUpdateCycles( uElapsedCycles ); + else + g_pNTSC_FuncVideoUpdate( uElapsedCycles ); +// NTSC_END + CheckInterruptSources(uExecutedCycles); NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz); IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz); diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index 80b800fa..120cbd5b 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -106,6 +106,11 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) UINT uExtraCycles = 0; BYTE iOpcode; +// NTSC_BEGIN + ULONG uElapsedCycles; + ULONG uPreviousCycles = uExecutedCycles; +// NTSC_END + if (g_ActiveCPU == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) @@ -648,6 +653,14 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) } #undef $ +// NTSC_BEGIN + uElapsedCycles = uExecutedCycles - uPreviousCycles; + if( g_bFullSpeed ) + NTSC_VideoUpdateCycles( uElapsedCycles ); + else + g_pNTSC_FuncVideoUpdate( uElapsedCycles ); +// NTSC_END + CheckInterruptSources(uExecutedCycles); NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz); IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz); diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp index 78ba4116..a5c47884 100644 --- a/source/Configuration/PageConfig.cpp +++ b/source/Configuration/PageConfig.cpp @@ -114,7 +114,7 @@ BOOL CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM break; case IDC_MONOCOLOR: - VideoChooseColor(); + VideoChooseMonochromeColor(); break; case IDC_CHECK_CONFIRM_REBOOT: diff --git a/source/Frame.h b/source/Frame.h index 322820b7..47af25a1 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -12,8 +12,15 @@ // 560 = Double Hi-Res // 384 = Doule Scan Line +// NTSC_BEGIN +#if 0 #define FRAMEBUFFER_W 560 #define FRAMEBUFFER_H 384 +#else + #define FRAMEBUFFER_W 600 + #define FRAMEBUFFER_H 420 +#endif +// NTSC_END // Direct Draw -- For Full Screen extern LPDIRECTDRAW g_pDD; diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 5c38beed..6587e458 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -40,6 +40,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Speaker.h" #include "Video.h" +// Prototypes (Public) + // Note: This is here and not in Video.h to prevent header include bloat. + // i.e. so we don't need to incude "Structs.h" for NTSC.cpp + DWORD VideoGetSnapshot(SS_IO_Video* pSS); + DWORD VideoSetSnapshot(SS_IO_Video* pSS); #define DEFAULT_SNAPSHOT_NAME "SaveState.aws" diff --git a/source/StdAfx.h b/source/StdAfx.h index 2e0d77a7..010d50f8 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -25,6 +25,7 @@ #include #include #include +#include // uint8_t #include #include // WM_MOUSEWHEEL diff --git a/source/Video.cpp b/source/Video.cpp index ca6dbfee..a653c44b 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Memory.h" #include "Registry.h" #include "Video.h" +#include "NTSC.h" #include "..\resource\resource.h" #include "Configuration\PropertySheet.h" @@ -195,17 +196,6 @@ const BYTE DoubleHiresPalIndex[16] = { const int SRCOFFS_DHIRES = (SRCOFFS_HIRES + 512); // 1168 const int SRCOFFS_TOTAL = (SRCOFFS_DHIRES + 2560); // 3278 - enum VideoFlag_e - { - VF_80COL = 0x00000001, - VF_DHIRES = 0x00000002, - VF_HIRES = 0x00000004, - VF_80STORE= 0x00000008, - VF_MIXED = 0x00000010, - VF_PAGE2 = 0x00000020, - VF_TEXT = 0x00000040 - }; - #define SW_80COL (g_uVideoMode & VF_80COL) #define SW_DHIRES (g_uVideoMode & VF_DHIRES) #define SW_HIRES (g_uVideoMode & VF_HIRES) @@ -223,6 +213,13 @@ const BYTE DoubleHiresPalIndex[16] = { #define HGR_MATRIX_YOFFSET 2 // For tv emulation HGR Video Mode +// Globals (Public) + + uint8_t *g_pFramebufferbits = NULL; // last drawn frame + int g_nAltCharSetOffset = 0; // alternate character set + +// Globals (Private) + // video scanner constants int const kHBurstClock = 53; // clock when Color Burst starts int const kHBurstClocks = 4; // clocks per Color Burst duration @@ -246,7 +243,6 @@ static COLORREF customcolors[256]; // MONOCHROME is last custom color static HBITMAP g_hDeviceBitmap; static HDC g_hDeviceDC; - LPBYTE g_pFramebufferbits = NULL; // last drawn frame static LPBITMAPINFO g_pFramebufferinfo = NULL; static LPBYTE g_aFrameBufferOffset[FRAMEBUFFER_H]; // array of pointers to start of each scanline @@ -270,7 +266,6 @@ static BYTE colormixbuffer[6]; static WORD colormixmap[6][6][6]; // -static int g_nAltCharSetOffset = 0; // alternate character set static /*bool*/ UINT g_VideoForceFullRedraw = 1; static bool g_bVideoUpdatedThisFrame = false; @@ -451,6 +446,9 @@ void CreateFrameOffsetTable (LPBYTE addr, LONG pitch) //=========================================================================== void VideoInitialize () { + // RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET + VideoResetState(); + // CREATE A BUFFER FOR AN IMAGE OF THE LAST DRAWN MEMORY vidlastmem = (LPBYTE)VirtualAlloc(NULL,0x10000,MEM_COMMIT,PAGE_READWRITE); ZeroMemory(vidlastmem,0x10000); @@ -466,47 +464,15 @@ void VideoInitialize () PAGE_READWRITE); ZeroMemory(g_pFramebufferinfo,sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)); - g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - g_pFramebufferinfo->bmiHeader.biWidth = FRAMEBUFFER_W; - g_pFramebufferinfo->bmiHeader.biHeight = FRAMEBUFFER_H; - g_pFramebufferinfo->bmiHeader.biPlanes = 1; - g_pFramebufferinfo->bmiHeader.biBitCount = 8; - g_pFramebufferinfo->bmiHeader.biClrUsed = 256; + g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + g_pFramebufferinfo->bmiHeader.biWidth = FRAMEBUFFER_W; + g_pFramebufferinfo->bmiHeader.biHeight = FRAMEBUFFER_H; + g_pFramebufferinfo->bmiHeader.biPlanes = 1; + g_pFramebufferinfo->bmiHeader.biBitCount = 32; + g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB; + g_pFramebufferinfo->bmiHeader.biClrUsed = 0; - // CREATE A BITMAPINFO STRUCTURE FOR THE SOURCE IMAGE - g_pSourceHeader = (LPBITMAPINFO)VirtualAlloc( - NULL, - sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), - MEM_COMMIT, - PAGE_READWRITE); - - ZeroMemory(g_pSourceHeader,sizeof(BITMAPINFOHEADER)); - g_pSourceHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - g_pSourceHeader->bmiHeader.biWidth = SRCOFFS_TOTAL; - g_pSourceHeader->bmiHeader.biHeight = 512; - g_pSourceHeader->bmiHeader.biPlanes = 1; - g_pSourceHeader->bmiHeader.biBitCount = 8; - g_pSourceHeader->bmiHeader.biClrUsed = 256; - - // VideoReinitialize() ... except we set the frame buffer palette.... - V_CreateIdentityPalette(); - - //RGB() -> none - //PALETTERGB() -> PC_EXPLICIT - //??? RGB() -> PC_NOCOLLAPSE - for( int iColor = 0; iColor < NUM_COLOR_PALETTE; iColor++ ) - customcolors[ iColor ] = ((DWORD)PC_EXPLICIT << 24) | RGB( - g_pFramebufferinfo->bmiColors[iColor].rgbRed, - g_pFramebufferinfo->bmiColors[iColor].rgbGreen, - g_pFramebufferinfo->bmiColors[iColor].rgbBlue - ); - - // CREATE THE FRAME BUFFER DIB SECTION AND DEVICE CONTEXT, - // CREATE THE SOURCE IMAGE DIB SECTION AND DRAW INTO THE SOURCE BIT BUFFER - V_CreateDIBSections(); - - // RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET - VideoResetState(); + NTSC_VideoCreateDIBSection(); } //=========================================================================== @@ -2329,8 +2295,9 @@ BYTE VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) return (r & ~0x80) | ((bVblBar) ? 0x80 : 0); } +// This is called from PageConfig //=========================================================================== -void VideoChooseColor () +void VideoChooseMonochromeColor () { CHOOSECOLOR cc; ZeroMemory(&cc,sizeof(CHOOSECOLOR)); @@ -2595,6 +2562,20 @@ VideoUpdateFuncPtr_t VideoRefreshScreen () DebugRefresh(0); #endif +// NTSC_BEGIN: wsVideoRefresh() + LPBYTE pDstFrameBufferBits = 0; + LONG pitch = 0; + HDC hFrameDC = FrameGetVideoDC(&pDstFrameBufferBits,&pitch); + + if (hFrameDC) + { +// StretchBlt(hFrameDC,0,0,VIEWPORTCX,VIEWPORTCY,g_hDeviceDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,SRCCOPY); + StretchBlt(hFrameDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,g_hDeviceDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,SRCCOPY); + GdiFlush(); + } + return NULL; +// NTSC_END + // CHECK EACH CELL FOR CHANGED BYTES. REDRAW PIXELS FOR THE CHANGED BYTES // IN THE FRAME BUFFER. MARK CELLS IN WHICH REDRAWING HAS TAKEN PLACE AS // DIRTY. @@ -2779,8 +2760,8 @@ void _Video_RedrawScreen( VideoUpdateFuncPtr_t pfUpdate, bool bMixed ) //=========================================================================== void VideoReinitialize () { - V_CreateIdentityPalette(); - V_CreateDIBSections(); + NTSC_VideoInitAppleType(); + NTSC_SetVideoStyle(); } @@ -2803,10 +2784,10 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) switch (address) { - case 0x00: g_uVideoMode &= ~VF_80STORE; break; - case 0x01: g_uVideoMode |= VF_80STORE; break; - case 0x0C: if (!IS_APPLE2) g_uVideoMode &= ~VF_80COL; break; - case 0x0D: if (!IS_APPLE2) g_uVideoMode |= VF_80COL; break; + case 0x00: g_uVideoMode &= ~VF_80STORE; ; break; + case 0x01: g_uVideoMode |= VF_80STORE; ; break; + case 0x0C: if (!IS_APPLE2) g_uVideoMode &= ~VF_80COL; NTSC_SetVideoTextMode(40); break; + case 0x0D: if (!IS_APPLE2) g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80); break; case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off case 0x0F: if (!IS_APPLE2) g_nAltCharSetOffset = 256; break; // Alternate char set on case 0x50: g_uVideoMode &= ~VF_TEXT; break; @@ -2821,6 +2802,10 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break; } +// NTSC_BEGIN + NTSC_SetVideoMode( g_uVideoMode ); +// NTSC_END + if (SW_80STORE) g_uVideoMode &= ~VF_PAGE2; @@ -3316,7 +3301,7 @@ void Video_MakeScreenShot(FILE *pFile) // Write Pixel Data // No need to use GetDibBits() since we already have http://msdn.microsoft.com/en-us/library/ms532334.aspx // @reference: "Storing an Image" http://msdn.microsoft.com/en-us/library/ms532340(VS.85).aspx - pSrc = ((u8*)g_pFramebufferbits); + pSrc = ((uint8_t*)g_pFramebufferbits); nLen = g_tBmpHeader.nWidthPixels * g_tBmpHeader.nHeightPixels * g_tBmpHeader.nBitsPerPixel / 8; if( g_iScreenshotType == SCREENSHOT_280x192 ) @@ -3351,10 +3336,10 @@ void Video_MakeScreenShot(FILE *pFile) TargaHeader_t *pHeader = &g_tTargaHeader; memset( (void*)pHeader, 0, sizeof( TargaHeader_t ) ); - pHeader->iImageType = TARGA_RGB; + pHeader->iImageType = TARGA_RGB; pHeader->nWidthPixels = FRAMEBUFFER_W; pHeader->nHeightPixels = FRAMEBUFFER_H; - pHeader->nBitsPerPixel = 24; + pHeader->nBitsPerPixel = 24; #endif // SCREENSHOT_TGA } @@ -3393,3 +3378,36 @@ void Config_Save_Video() REGSAVE(TEXT(REGVALUE_VIDEO_HALF_SCAN_LINES),g_uHalfScanLines); REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),monochrome); } + +// ____________________________________________________________________ + +//=========================================================================== +void NTSC_VideoCreateDIBSection() +{ + // CREATE THE DEVICE CONTEXT + HWND window = GetDesktopWindow(); + HDC dc = GetDC(window); + if (g_hDeviceDC) + { + DeleteDC(g_hDeviceDC); + } + g_hDeviceDC = CreateCompatibleDC(dc); + + // CREATE THE FRAME BUFFER DIB SECTION + if (g_hDeviceBitmap) + DeleteObject(g_hDeviceBitmap); + g_hDeviceBitmap = CreateDIBSection( + dc, + g_pFramebufferinfo, + DIB_RGB_COLORS, + (LPVOID *)&g_pFramebufferbits,0,0 + ); + SelectObject(g_hDeviceDC,g_hDeviceBitmap); + + // CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE FRAME BUFFER + // DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER + ZeroMemory( g_pFramebufferbits, FRAMEBUFFER_W*FRAMEBUFFER_H*4 ); + + NTSC_VideoInit( g_pFramebufferbits ); +} + diff --git a/source/Video.h b/source/Video.h index 9aa270b9..1fb3075e 100644 --- a/source/Video.h +++ b/source/Video.h @@ -8,8 +8,8 @@ { VT_MONO_HALFPIXEL_REAL // uses custom monochrome , VT_COLOR_STANDARD - , VT_COLOR_TEXT_OPTIMIZED - , VT_COLOR_TVEMU + , VT_COLOR_TEXT_OPTIMIZED + , VT_COLOR_TVEMU , VT_MONO_AMBER // now half pixel , VT_MONO_GREEN // now half pixel , VT_MONO_WHITE // now half pixel @@ -19,28 +19,39 @@ extern TCHAR g_aVideoChoices[]; extern char *g_apVideoModeDesc[ NUM_VIDEO_MODES ]; -enum AppleFont_e -{ - // 40-Column mode is 1x Zoom (default) - // 80-Column mode is ~0.75x Zoom (7 x 16) - // Tiny mode is 0.5 zoom (7x8) for debugger - APPLE_FONT_WIDTH = 14, // in pixels - APPLE_FONT_HEIGHT = 16, // in pixels + enum VideoFlag_e + { + VF_80COL = 0x00000001, + VF_DHIRES = 0x00000002, + VF_HIRES = 0x00000004, + VF_80STORE= 0x00000008, // was called VF_MASK2 + VF_MIXED = 0x00000010, + VF_PAGE2 = 0x00000020, + VF_TEXT = 0x00000040 + }; - // Each cell has a reserved aligned pixel area (grid spacing) - APPLE_FONT_CELL_WIDTH = 16, - APPLE_FONT_CELL_HEIGHT = 16, + enum AppleFont_e + { + // 40-Column mode is 1x Zoom (default) + // 80-Column mode is ~0.75x Zoom (7 x 16) + // Tiny mode is 0.5 zoom (7x8) for debugger + APPLE_FONT_WIDTH = 14, // in pixels + APPLE_FONT_HEIGHT = 16, // in pixels - // The bitmap contains 3 regions - // Each region is 256x256 pixels = 16x16 chars - APPLE_FONT_X_REGIONSIZE = 256, // in pixelx - APPLE_FONT_Y_REGIONSIZE = 256, // in pixels + // Each cell has a reserved aligned pixel area (grid spacing) + APPLE_FONT_CELL_WIDTH = 16, + APPLE_FONT_CELL_HEIGHT = 16, - // Starting Y offsets (pixels) for the regions - APPLE_FONT_Y_APPLE_2PLUS = 0, // ][+ - APPLE_FONT_Y_APPLE_80COL = 256, // //e (inc. Mouse Text) - APPLE_FONT_Y_APPLE_40COL = 512, // ][ -}; + // The bitmap contains 3 regions + // Each region is 256x256 pixels = 16x16 chars + APPLE_FONT_X_REGIONSIZE = 256, // in pixelx + APPLE_FONT_Y_REGIONSIZE = 256, // in pixels + + // Starting Y offsets (pixels) for the regions + APPLE_FONT_Y_APPLE_2PLUS = 0, // ][+ + APPLE_FONT_Y_APPLE_80COL = 256, // //e (inc. Mouse Text) + APPLE_FONT_Y_APPLE_40COL = 512, // ][ + }; // Globals __________________________________________________________ @@ -49,7 +60,8 @@ extern HBITMAP g_hLogoBitmap; extern COLORREF monochrome; // saved extern DWORD g_eVideoType; // saved extern DWORD g_uHalfScanLines; // saved -extern LPBYTE g_pFramebufferbits; +extern uint8_t *g_pFramebufferbits; +extern int g_nAltCharSetOffset; // alternate character set typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int); @@ -59,7 +71,7 @@ void CreateColorMixMap(); BOOL VideoApparentlyDirty (); void VideoBenchmark (); -void VideoChooseColor (); +void VideoChooseMonochromeColor (); // FIXME: Should be moved to PageConfig and call VideoSetMonochromeColor() void VideoDestroy (); void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale); void VideoDisplayLogo (); @@ -85,9 +97,6 @@ bool VideoGetSWAltCharSet(void); void VideoSetForceFullRedraw(void); -DWORD VideoGetSnapshot(SS_IO_Video* pSS); -DWORD VideoSetSnapshot(SS_IO_Video* pSS); - void _Video_Dirty(); void _Video_RedrawScreen( VideoUpdateFuncPtr_t update, bool bMixed = false ); void _Video_SetupBanks( bool bBank2 ); From e681c97c3b2fe94b94673dfe1e061a75050d3bee Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 31 Dec 2014 14:53:55 -0800 Subject: [PATCH 002/121] Added NTSC files to Solution --- ApplewinExpress10.00.vcxproj.filters | 6 + source/NTSC.cpp | 1185 ++++++++++++++++++++++++++ source/NTSC.h | 30 + source/NTSC_CharSet.cpp | 215 +++++ source/NTSC_CharSet.h | 27 + 5 files changed, 1463 insertions(+) create mode 100644 source/NTSC.cpp create mode 100644 source/NTSC.h create mode 100644 source/NTSC_CharSet.cpp create mode 100644 source/NTSC_CharSet.h diff --git a/ApplewinExpress10.00.vcxproj.filters b/ApplewinExpress10.00.vcxproj.filters index 29487593..69cbe148 100644 --- a/ApplewinExpress10.00.vcxproj.filters +++ b/ApplewinExpress10.00.vcxproj.filters @@ -212,6 +212,9 @@ Source + + Source\Video + @@ -451,6 +454,9 @@ Source + + Source\Video + diff --git a/source/NTSC.cpp b/source/NTSC.cpp new file mode 100644 index 00000000..7f0b4e49 --- /dev/null +++ b/source/NTSC.cpp @@ -0,0 +1,1185 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 2010-2011, William S Simms +Copyright (C) 2014 Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Includes + #include "StdAfx.h" + #include "AppleWin.h" + #include "CPU.h" + #include "Frame.h" // FRAMEBUFFER_W FRAMEBUFFER_H + #include "Memory.h" // MemGetMainPtr() MemGetBankPtr() + #include "Video.h" // g_pFramebufferbits + + #include "NTSC.h" + #include "NTSC_CharSet.cpp" + + //LPBYTE MemGetMainPtr(const WORD); + //LPBYTE MemGetBankPtr(const UINT nBank); + +// Defines + #define PI 3.1415926535898f + #define RAD_45 PI*0.25f + #define RAD_90 PI*0.5f + #define RAD_360 PI*2.f + + #define DEG_TO_RAD(x) (PI*(x)/180.f) // 2PI=360, PI=180,PI/2=90,PI/4=45 + + #ifndef CHROMA_BLUR + #define CHROMA_BLUR 1 // Default: 1; 1 = blur along ~8 pixels; 0 = sharper + #endif + + #ifndef CHROMA_FILTER + #define CHROMA_FILTER 1 // If no chroma blur; 0 = use chroma as-is, 1 = soft chroma blur, strong color fringes 2 = more blur, muted chroma fringe + #endif + + #if CHROMA_BLUR + #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees + #else // sharpness is higher, less color bleed + #if CHROMA_FILTER == 2 + #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = signal_prefilter(z); + #else + // #define CYCLESTART DEG_TO_RAD(90) // (PI*0.5) // PI/2 = 90 degrees // HGR: Great, GR: fail on brown + #define CYCLESTART DEG_TO_RAD(115.f) // GR perfect match of slow method + #endif + #endif + + #define HGR_TEST_PATTERN 0 + +// Globals (Public) ___________________________________________________ + uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262 + uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible + +// Globals (Private) __________________________________________________ + static int g_nVideoCharSet = 0; + static int g_nVideoMixed = 0; + static int g_nHiresPage = 1; + static int g_nTextPage = 1; + + // Understanding the Apple II, Timing Generation and the Video Scanner, Pg 3-11 + // Vertical Scanning + // Horizontal Scanning + // "There are exactly 17030 (65 x 262) 6502 cycles in every television scan of an American Apple." + #define VIDEO_SCANNER_MAX_HORZ 65 // TODO: use Video.cpp: kHClocks + #define VIDEO_SCANNER_MAX_VERT 262 // TODO: use Video.cpp: kNTSCScanLines + + #define VIDEO_SCANNER_HORZ_START 25 // first displayable horz scanner index + #define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text + #define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines + + uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ]; + unsigned char * g_NTSC_Lines[384]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + + static unsigned g_nTextFlashCounter = 0; + static unsigned g_nTextFlashMask = 0; + + static unsigned g_aPixelMaskGR[16]; + static uint16_t g_aPixelDoubleMaskHGR[128]; // hgrbits -> g_aPixelDoubleMaskHGR: 7-bit mono 280 pixels to 560 pixel doubling + +#define UpdateVideoAddressTXT() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] + g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400)) +#define UpdateVideoAddressHGR() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)) // BUG? g_pHorzClockOffset + + static unsigned char *vbp0; + static int g_nLastColumnPixelNTSC; + static int g_nColorBurstPixels; + + #define INITIAL_COLOR_PHASE 0 + static int g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; + static int g_nSignalBitsNTSC = 0; + + #define NTSC_NUM_PHASES 4 + #define NTSC_NUM_SEQUENCES 4096 + enum ColorChannel + { // Win32 DIB: BGRA format + _B = 0, + _G = 1, + _R = 2, + _A = 3, + NUM_COLOR_CHANNELS = 4 + }; + + static unsigned char g_aNTSCMonoMonitor [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + static unsigned char g_aNTSCColorMonitor [NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + static unsigned char g_aNTSCMonoTelevision [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + static unsigned char g_aNTSCColorTelevision[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + + #define NUM_SIGZEROS 2 + #define NUM_SIGPOLES 2 + #define SIGGAIN 7.614490548f + + #define NUM_LUMZEROS 2 + #define NUM_LUMPOLES 2 + //#define LUMGAIN 1.062635655e+01 + //#define LUMCOEF1 -0.3412038399 + //#define LUMCOEF2 0.9647813115 + #define LUMGAIN 13.71331570f + #define LUMCOEF1 -0.3961075449f + #define LUMCOEF2 1.1044202472f + + #define NUM_CHRZEROS 2 + #define NUM_CHRPOLES 2 + #define CHRGAIN 7.438011255f + +// Tables + static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] = + { + 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80, + 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80, + 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80, + 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80, + + 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80, + 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80, + 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80, + 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80, + + 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80, + 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80, + 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80, + 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80, + + 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80, + 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80, + 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80, + 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80, + + 0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80 + }; + + static unsigned g_aClockVertOffsetsTXT[33] = + { + 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, + 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, + 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, + 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x380 + }; + + static unsigned APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = + { + {0x1068,0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F, + 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077, + 0x1078,0x1079,0x107A,0x107B,0x107C,0x107D,0x107E,0x107F, + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027}, + + {0x1010,0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017, + 0x1018,0x1019,0x101A,0x101B,0x101C,0x101D,0x101E,0x101F, + 0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027, + 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F}, + + {0x1038,0x1038,0x1039,0x103A,0x103B,0x103C,0x103D,0x103E,0x103F, + 0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047, + 0x1048,0x1049,0x104A,0x104B,0x104C,0x104D,0x104E,0x104F, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077}, + + {0x1060,0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067, + 0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F, + 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077, + 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}, + + {0x1060,0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067, + 0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F, + 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077, + 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} + }; + + static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = + { + {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x106F, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027}, + + {0x0010,0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F}, + + {0x0038,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077}, + + {0x0060,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}, + + {0x0060,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} + }; + + static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; + + static void (* g_pNTSC_FuncVideoText )(long) = NTSC_UpdateVideoText40; + void (* g_pNTSC_FuncVideoUpdate)(long) = NTSC_UpdateVideoText40; + +// Prototypes + // prototype from CPU.h + //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles); + // prototypes from Memory.h + //unsigned char * MemGetAuxPtr (unsigned short); + //unsigned char * MemGetMainPtr (unsigned short); + void init_chroma_phase_table(); + void updateColorPhase(); + void updateVideoHorzEOL(); + +//=========================================================================== +inline float clampZeroOne( const float & x ) +{ + if (x < 0.f) return 0.f; + if (x > 1.f) return 1.f; + /* ...... */ return x; +} + +//=========================================================================== +inline void updateColorPhase() +{ + g_nColorPhaseNTSC++; + g_nColorPhaseNTSC &= 3; +} + +//=========================================================================== +void NTSC_VideoInitAppleType () +{ + int model = g_Apple2Type; + + // anything other than low bit set means not II/II+ + if (model & 0xFFFE) + g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; + else + g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; +} + +static void init_video_tables (void) +{ + /* + Convert 7-bit monochrome luminance to 14-bit double pixel luminance + Chroma will be applied later based on the color phase in ntscColorDoublePixel( luminanceBit ) + 0x001 -> 0x0003 + 0x002 -> 0x000C + 0x004 -> 0x0030 + 0x008 -> 0x00C0 + 0x100 -> 0x4000 + */ + for (uint8_t byte = 0; byte < 0x80; byte++ ) // Optimization: hgrbits second 128 entries are mirror of first 128 + for (uint8_t bits = 0; bits < 7; bits++ ) // high bit = half pixel shift; pre-optimization: bits < 8 + if (byte & (1 << bits)) // pow2 mask + g_aPixelDoubleMaskHGR[byte] |= 3 << (bits*2); + + for ( uint16_t color = 0; color < 16; color++ ) + g_aPixelMaskGR[ color ] = (color << 12) | (color << 8) | (color << 4) | (color << 0); +} + +// sadly float64 precision is needed +#define real double + +static real signal_prefilter (real z) +{ + static real xv[NUM_SIGZEROS + 1] = { 0,0,0 }; + static real yv[NUM_SIGPOLES + 1] = { 0,0,0 }; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / SIGGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (-0.2718798058f * yv[0]) + (0.7465656072f * yv[1]); + + return yv[2]; +} + +static real luma0_filter (real z) +{ + static real xv[NUM_LUMZEROS + 1]; + static real yv[NUM_LUMPOLES + 1]; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / LUMGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); + + return yv[2]; +} + +static real luma1_filter (real z) +{ + static real xv[NUM_LUMZEROS + 1]; + static real yv[NUM_LUMPOLES + 1]; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / LUMGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[0] + xv[2] + (2 * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); + + return yv[2]; +} + +static real chroma_filter (real z) +{ + static real xv[NUM_CHRZEROS + 1]; + static real yv[NUM_CHRPOLES + 1]; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / CHRGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[2] - xv[0] + (-0.7318893645f * yv[0]) + (1.2336442711f * yv[1]); + + return yv[2]; +} + +// Build the 4 phase chroma lookup table +// The YI'Q' colors are hard-coded +//=========================================================================== +static void init_chroma_phase_table (void) +{ + int phase,s,t,n; + real z,y0,y1,c,i,q; + real phi,zz; + float brightness; + double r64,g64,b64; + float r32,g32,b32; + + for (phase = 0; phase < 4; ++phase) + { + phi = (phase * RAD_90) + CYCLESTART; + for (s = 0; s < NTSC_NUM_SEQUENCES; ++s) + { + t = s; + y0 = y1 = c = i = q = 0.0; + + for (n = 0; n < 12; ++n) + { + z = (real)(0 != (t & 0x800)); + t = t << 1; + + for(int k = 0; k < 2; k++ ) + { +#if CHROMA_BLUR + //z = z * 1.25; + zz = signal_prefilter(z); + c = chroma_filter(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + y0 = luma0_filter(zz); + y1 = luma1_filter(zz - c); +#else // CHROMA_BLUR + y0 = y0 + (z - y0) / 4.0; + y1 = y0; // fix TV mode + + #if CHROMA_FILTER == 0 + c = z; // sharper; "Mostly" correct _if_ CYCLESTART = 115 degrees + #endif // CHROMA_FILTER + #if CHROMA_FILTER == 1 // soft chroma blur, strong color fringes + // NOTE: This has incorrect colors! Chroma is (115-45)=70 degrees out of phase! violet <-> orange, green <-> blue + c = (z - y0); // Original -- smoother, white is solid, brighter; other colors + // -> + // c = (z - (y0 + (z-y0)/4)) + // c = z - y0 - (z-y0)/4 + // c = z - y0 - z/4 + y0/4 + // c = z-z/4 - y0+y0/4; // Which is clearly wrong, unless CYCLESTART DEG_TO_RAD(115) + // This mode looks the most accurate for white, has better color fringes + #endif + #if CHROMA_FILTER == 2 // more blur, muted chroma fringe + // White has too much ringing, and the color fringes are muted + c = signal_prefilter(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + #endif +#endif // CHROMA_BLUR + c = c * 2.f; + i = i + (c * cos(phi) - i) / 8.f; + q = q + (c * sin(phi) - q) / 8.f; + + phi += RAD_45; //(PI / 4); + if (fabs((RAD_360) - phi) < 0.001) + phi = phi - RAD_360; // 2 * PI; + } // k + } // samples + + brightness = clampZeroOne( (float)z ); + g_aNTSCMonoMonitor[s][_B] = (uint8_t)(brightness * 255); + g_aNTSCMonoMonitor[s][_G] = (uint8_t)(brightness * 255); + g_aNTSCMonoMonitor[s][_R] = (uint8_t)(brightness * 255); + g_aNTSCMonoMonitor[s][_A] = 255; + + brightness = clampZeroOne( (float)y1); + g_aNTSCMonoTelevision[s][_B] = (uint8_t)(brightness * 255); + g_aNTSCMonoTelevision[s][_G] = (uint8_t)(brightness * 255); + g_aNTSCMonoTelevision[s][_R] = (uint8_t)(brightness * 255); + g_aNTSCMonoTelevision[s][_A] = 255; + + /* + YI'V' to RGB + + [r g b] = [y i v][ 1 1 1 ] + [0.956 -0.272 -1.105] + [0.621 -0.647 1.702] + + [r] [1 0.956 0.621][y] + [g] = [1 -0.272 -0.647][i] + [b] [1 -1.105 1.702][v] + */ + #define I_TO_R 0.956f + #define I_TO_G -0.272f + #define I_TO_B -1.105f + + #define Q_TO_R 0.621f + #define Q_TO_G -0.647f + #define Q_TO_B 1.702f + + r64 = y0 + (I_TO_R * i) + (Q_TO_R * q); + g64 = y0 + (I_TO_G * i) + (Q_TO_G * q); + b64 = y0 + (I_TO_B * i) + (Q_TO_B * q); + + b32 = clampZeroOne( (float)b64); + g32 = clampZeroOne( (float)g64); + r32 = clampZeroOne( (float)r64); + + g_aNTSCColorMonitor[phase][s][_B] = (uint8_t)(b32 * 255); + g_aNTSCColorMonitor[phase][s][_G] = (uint8_t)(g32 * 255); + g_aNTSCColorMonitor[phase][s][_R] = (uint8_t)(r32 * 255); + g_aNTSCColorMonitor[phase][s][_A] = 255; + + r64 = y1 + (I_TO_R * i) + (Q_TO_R * q); + g64 = y1 + (I_TO_G * i) + (Q_TO_G * q); + b64 = y1 + (I_TO_B * i) + (Q_TO_B * q); + + b32 = clampZeroOne( (float)b64 ); + g32 = clampZeroOne( (float)g64 ); + r32 = clampZeroOne( (float)r64 ); + + g_aNTSCColorTelevision[phase][s][_B] = (uint8_t)(b32 * 255); + g_aNTSCColorTelevision[phase][s][_G] = (uint8_t)(g32 * 255); + g_aNTSCColorTelevision[phase][s][_R] = (uint8_t)(r32 * 255); + g_aNTSCColorTelevision[phase][s][_A] = 255; + } + } +} + +//=========================================================================== +void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit +{ + make_csbits(); + init_video_tables(); + init_chroma_phase_table(); + + for (int y = 0; y < 384; y++) + g_NTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; + + vbp0 = g_NTSC_Lines[0]; // wsLines + +#if HGR_TEST_PATTERN +// Michael -- Init HGR to almost all-possible-combinations +// CALL-151 +// C050 C053 C057 + unsigned char b = 0; + unsigned char *main, *aux; + + for( unsigned page = 0; page < 2; page++ ) + { + for( unsigned w = 0; w < 2; w++ ) // 16 cols + { + for( unsigned z = 0; z < 2; z++ ) // 8 cols + { + b = 0; // 4 columns * 64 rows + for( unsigned x = 0; x < 4; x++ ) // 4 cols + { + for( unsigned y = 0; y < 64; y++ ) // 1 col + { + unsigned y2 = y*2; + ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; + ad += 0x2000*page; + main = MemGetMainPtr(ad); + aux = MemGetAuxPtr (ad); + main[0] = b; main[1] = w + page*0x80; + aux [0] = z; aux [1] = 0; + + y2 = y*2 + 1; + ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; + ad += 0x2000*page; + main = MemGetMainPtr(ad); + aux = MemGetAuxPtr (ad); + main[0] = 0; main[1] = w + page*0x80; + aux [0] = b; aux [1] = 0; + + b++; + } + } + } + } + } +#endif + +} + +#define SINGLEPIXEL(signal,table) \ + do { \ + unsigned int *cp, *mp; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ + *((unsigned int *)vbp0) = *cp; \ + mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ + *mp = ((*cp & 0x00fcfcfc) >> 2) + 0xff000000; \ + vbp0 += 4; \ + } while(0) + +#define SINGLETVPIXEL(signal,table) \ + do { \ + unsigned int ntscp, prevp, betwp; \ + unsigned int *prevlin, *between; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ + between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ + ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ + prevp = *prevlin; \ + betwp = ntscp - ((ntscp & 0x00fcfcfc) >> 2); \ + *between = betwp | 0xff000000; \ + *((unsigned int *)vbp0) = ntscp; \ + vbp0 += 4; \ + } while(0) + +#define DOUBLEPIXEL(signal,table) \ + do { \ + unsigned int *cp, *mp; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ + mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ + *((unsigned int *)vbp0) = *mp = *cp; \ + vbp0 += 4; \ + } while(0) + +#define DOUBLETVPIXEL(signal,table) \ + do { \ + unsigned int ntscp, prevp, betwp; \ + unsigned int *prevlin, *between; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ + between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ + ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ + prevp = *prevlin; \ + betwp = ((ntscp & 0x00fefefe) >> 1) + ((prevp & 0x00fefefe) >> 1); \ + *between = betwp | 0xff000000; \ + *((unsigned int *)vbp0) = ntscp; \ + vbp0 += 4; \ + } while(0) + +static void ntscMonoSinglePixel (int compositeSignal) +{ + SINGLEPIXEL(compositeSignal, g_aNTSCMonoMonitor); +} + +static void ntscMonoDoublePixel (int compositeSignal) +{ + DOUBLEPIXEL(compositeSignal, g_aNTSCMonoMonitor); +} + +static void ntscColorSinglePixel (int compositeSignal) +{ + SINGLEPIXEL(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateColorPhase(); +} + +static void ntscColorDoublePixel (int compositeSignal) +{ + DOUBLEPIXEL(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateColorPhase(); +} + + +static void ntscMonoTVSinglePixel (int compositeSignal) +{ + SINGLETVPIXEL(compositeSignal, g_aNTSCMonoTelevision); +} + +static void ntscMonoTVDoublePixel (int compositeSignal) +{ + DOUBLETVPIXEL(compositeSignal, g_aNTSCMonoTelevision); +} + +static void ntscColorTVSinglePixel (int compositeSignal) +{ + SINGLETVPIXEL(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + updateColorPhase(); +} + +static void ntscColorTVDoublePixel (int compositeSignal) +{ + DOUBLETVPIXEL(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + updateColorPhase(); +} + +static void (*ntscMonoPixel)(int) = ntscMonoSinglePixel; +static void (*ntscColorPixel)(int) = ntscColorSinglePixel; + +//=========================================================================== +void NTSC_SetVideoStyle() // (int v, int s) +{ + int v = g_eVideoType; + int s = g_uHalfScanLines; + + switch (v) + { + case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: + if (s) { + ntscMonoPixel = ntscMonoTVSinglePixel; + ntscColorPixel = ntscColorTVSinglePixel; + } + else { + ntscMonoPixel = ntscMonoTVDoublePixel; + ntscColorPixel = ntscColorTVDoublePixel; + } + break; + + case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1: + default: + if (s) { + ntscMonoPixel = ntscMonoSinglePixel; + ntscColorPixel = ntscColorSinglePixel; + } + else { + ntscMonoPixel = ntscMonoDoublePixel; + ntscColorPixel = ntscColorDoublePixel; + } + break; + + case VT_COLOR_TEXT_OPTIMIZED: // VT_MONO_TV: //2: + if (s) { + ntscMonoPixel = ntscColorPixel = ntscMonoTVSinglePixel; + } + else { + ntscMonoPixel = ntscColorPixel = ntscMonoTVDoublePixel; + } + break; + + case VT_MONO_WHITE: //VT_MONO_MONITOR: //3: + if (s) { + ntscMonoPixel = ntscColorPixel = ntscMonoSinglePixel; + } + else { + ntscMonoPixel = ntscColorPixel = ntscMonoDoublePixel; + } + break; + } +} + +int NTSC_VideoIsVbl () +{ + return (g_nVideoClockVert >= VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockVert < VIDEO_SCANNER_MAX_VERT); +} + +unsigned char NTSC_VideoByte (unsigned long cycle) +{ + unsigned char * mem; + mem = MemGetMainPtr(g_aHorzClockMemAddress[ g_nVideoClockHorz ]); + return mem[0]; +} + +#define VIDEO_DRAW_BITS() do { \ + if (g_nColorBurstPixels < 2) \ + { \ + /* #1 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + /* #2 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + /* #3 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + /* #4 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + /* #5 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + /* #6 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + /* #7 of 7 */ \ + ntscMonoPixel(bt & 1); bt >>= 1; \ + ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1;\ + } \ + else \ + { \ + /* #1 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); bt >>= 1; \ + /* #2 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); bt >>= 1; \ + /* #3 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); bt >>= 1; \ + /* #4 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); bt >>= 1; \ + /* #5 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); bt >>= 1; \ + /* #6 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); bt >>= 1; \ + /* #7 of 7 */ \ + ntscColorPixel(bt & 1); bt >>= 1; \ + ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1;\ + } \ +} while(0) + +inline +void updateVideoHorzEOL() +{ + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + g_nVideoClockHorz = 0; + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + //VIDEO_DRAW_ENDLINE(); + if (g_nColorBurstPixels < 2) + { + ntscMonoPixel(g_nLastColumnPixelNTSC); + ntscMonoPixel(0); + ntscMonoPixel(0); + ntscMonoPixel(0); + } + else + { + ntscColorPixel(g_nLastColumnPixelNTSC); + ntscColorPixel(0); + ntscColorPixel(0); + ntscColorPixel(0); + } + } + + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + if (++g_nTextFlashCounter == 16) + { + g_nTextFlashCounter = 0; + g_nTextFlashMask ^= 0xffff; + } + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; + g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; + g_nLastColumnPixelNTSC = 0; + g_nSignalBitsNTSC = 0; + } + } +} + +// Light-weight Video Clock Update +//=========================================================================== +void NTSC_VideoUpdateCycles( long cycles ) +{ + for( ; cycles > 0; cycles-- ) + { + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + g_nVideoClockHorz = 0; + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + if (++g_nTextFlashCounter == 16) + { + g_nTextFlashCounter = 0; + g_nTextFlashMask ^= 0xffff; + } + + // Force full refresh + g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; + g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; + g_nLastColumnPixelNTSC = 0; + g_nSignalBitsNTSC = 0; + } + } + } +} + + +//=========================================================================== +void NTSC_UpdateVideoText40 (long ticks) +{ + unsigned ad, bt; + + for (; ticks; --ticks) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12) + { + if (g_nColorBurstPixels > 0) + g_nColorBurstPixels -= 1; + } + else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * main = MemGetMainPtr(ad); + + bt = g_aPixelDoubleMaskHGR[(csbits[g_nVideoCharSet][main[0]][g_nVideoClockVert & 7]) & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + if (0 == g_nVideoCharSet && 0x40 == (main[0] & 0xC0)) + bt ^= g_nTextFlashMask; + VIDEO_DRAW_BITS(); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoText80 (long ticks) +{ + unsigned int ad, bt, mbt, abt; + + for (; ticks; --ticks) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12) + { + if (g_nColorBurstPixels > 0) + g_nColorBurstPixels -= 1; + } + else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * aux = MemGetAuxPtr(ad); + unsigned char * main = MemGetMainPtr(ad); + + mbt = csbits[g_nVideoCharSet][main[0]][g_nVideoClockVert & 7]; + if (0 == g_nVideoCharSet && 0x40 == (main[0] & 0xC0)) mbt ^= g_nTextFlashMask; + + abt = csbits[g_nVideoCharSet][aux[0]][g_nVideoClockVert & 7]; + if (0 == g_nVideoCharSet && 0x40 == (aux[0] & 0xC0)) abt ^= g_nTextFlashMask; + + bt = (mbt << 7) | abt; + VIDEO_DRAW_BITS(); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores +{ + unsigned ad, bt; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText(ticks); + return; + } + + for (; ticks; --ticks) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * main = MemGetMainPtr(ad); + bt = g_aPixelDoubleMaskHGR[(0xFF & g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits + VIDEO_DRAW_BITS(); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoLores40 (long ticks) +{ + unsigned ad, bt; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText(ticks); + return; + } + + for (; ticks; --ticks) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * main = MemGetMainPtr(ad); + bt = g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> ((1 - (g_nVideoClockHorz & 1)) * 2); + VIDEO_DRAW_BITS(); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores +{ + unsigned ad, bt, abt, mbt; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText(ticks); + return; + } + + for (; ticks; --ticks) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * aux = MemGetAuxPtr(ad); + unsigned char * main = MemGetMainPtr(ad); + + abt = g_aPixelMaskGR[(aux [0] >> (g_nVideoClockVert & 4)) & 0xF] >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); + mbt = g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); + bt = (mbt << 7) | (abt & 0x7f); + + VIDEO_DRAW_BITS(); + g_nLastColumnPixelNTSC = bt & 1; + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires +{ + unsigned ad, bt; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText(ticks); + return; + } + + for (; ticks; --ticks) + { + UpdateVideoAddressHGR(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * aux = MemGetAuxPtr(ad); + unsigned char * main = MemGetMainPtr(ad); + + bt = ((main[0] & 0x7f) << 7) | (aux[0] & 0x7f); + bt = (bt << 1) | g_nLastColumnPixelNTSC; + VIDEO_DRAW_BITS(); + g_nLastColumnPixelNTSC = bt & 1; + } + } + updateVideoHorzEOL(); + } +} + + +//=========================================================================== +void NTSC_UpdateVideoHires40 (long ticks) +{ + unsigned ad, bt; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText(ticks); + return; + } + + for (; ticks; --ticks) + { + UpdateVideoAddressHGR(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * main = MemGetMainPtr(ad); + + bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + if (main[0] & 0x80) bt = (bt << 1) | g_nLastColumnPixelNTSC; + VIDEO_DRAW_BITS(); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDblHires40 (long ticks) // wsUpdateVideoHires0 +{ + unsigned ad, bt; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText(ticks); + return; + } + + for (; ticks; --ticks) + { + UpdateVideoAddressHGR(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + unsigned char * main = MemGetMainPtr(ad); + bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + VIDEO_DRAW_BITS(); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_SetVideoTextMode( int cols ) +{ + if( cols == 40 ) + g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; + else + g_pNTSC_FuncVideoText = NTSC_UpdateVideoText80; +} + +//=========================================================================== +void NTSC_SetVideoMode( int bVideoModeFlags ) +{ + g_nVideoMixed = bVideoModeFlags & VF_MIXED; + g_nVideoCharSet = g_nAltCharSetOffset; + + g_nTextPage = 1; + g_nHiresPage = 1; + if (bVideoModeFlags & VF_PAGE2) { + if (0 == (bVideoModeFlags & VF_80STORE)) { + g_nTextPage = 2; + g_nHiresPage = 2; + } + } + + if (bVideoModeFlags & VF_TEXT) { + if (bVideoModeFlags & VF_80COL) + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText80; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40; + } + else if (bVideoModeFlags & VF_HIRES) { + if (bVideoModeFlags & VF_DHIRES) + if (bVideoModeFlags & VF_80COL) + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires80; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires40; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoHires40; + } + else { + if (bVideoModeFlags & VF_DHIRES) + if (bVideoModeFlags & VF_80COL) + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores80; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores40; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoLores40; + } +} diff --git a/source/NTSC.h b/source/NTSC.h new file mode 100644 index 00000000..d2092891 --- /dev/null +++ b/source/NTSC.h @@ -0,0 +1,30 @@ +#define VIDEO_SCANNER_6502_CYCLES 17030 + +// Globals (Public) + + extern uint16_t g_nVideoClockVert; + extern uint16_t g_nVideoClockHorz; + extern uint8_t* g_NTSC_pLines[384]; + extern void (* g_pNTSC_FuncVideoUpdate)(long); + +// Prototypes (Public) ________________________________________________ + extern void NTSC_SetVideoTextMode( int cols ); + extern void NTSC_SetVideoMode( int flags ); + extern void NTSC_SetVideoStyle(); + + extern void NTSC_UpdateVideoText40 (long cycles); + extern void NTSC_UpdateVideoText80 (long cyckes); + extern void NTSC_UpdateVideoLores40 (long cycles); + extern void NTSC_UpdateVideoDblLores40(long cycles); + extern void NTSC_UpdateVideoDblLores80(long cycles); + extern void NTSC_UpdateVideoHires40 (long cycles); + extern void NTSC_UpdateVideoDblHires40(long cycles); + extern void NTSC_UpdateVideoDblHires80(long cycles); + + extern uint8_t NTSC_VideoByte(unsigned long); + extern void NTSC_VideoCreateDIBSection(); + extern void NTSC_VideoInit( uint8_t *pFramebuffer ); + extern void NTSC_VideoInitAppleType (); + extern int NTSC_VideoIsVbl(); + extern void NTSC_VideoUpdateCycles( long cycles ); + diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp new file mode 100644 index 00000000..4648b82a --- /dev/null +++ b/source/NTSC_CharSet.cpp @@ -0,0 +1,215 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 2010-2011, William S Simms + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "NTSC_CharSet.h" + +unsigned char csbits[2][256][8]; + +static const char *csstrs[] = { + " ### "," # "," #### "," ### "," #### "," ##### "," ##### "," #### ", + " # # "," # # "," # # "," # # "," # # "," # "," # "," # ", + " # # # "," # # "," # # "," # "," # # "," # "," # "," # ", + " # ### "," # # "," #### "," # "," # # "," #### "," #### "," # ", + " # ## "," ##### "," # # "," # "," # # "," # "," # "," # ## ", + " # "," # # "," # # "," # # "," # # "," # "," # "," # # ", + " #### "," # # "," #### "," ### "," #### "," ##### "," # "," #### ", + " "," "," "," "," "," "," "," ", + " # # "," ### "," # "," # # "," # "," # # "," # # "," ### ", + " # # "," # "," # "," # # "," # "," ## ## "," # # "," # # ", + " # # "," # "," # "," # # "," # "," # # # "," ## # "," # # ", + " ##### "," # "," # "," ## "," # "," # # # "," # # # "," # # ", + " # # "," # "," # "," # # "," # "," # # "," # ## "," # # ", + " # # "," # "," # # "," # # "," # "," # # "," # # "," # # ", + " # # "," ### "," ### "," # # "," ##### "," # # "," # # "," ### ", + " "," "," "," "," "," "," "," ", + " #### "," ### "," #### "," ### "," ##### "," # # "," # # "," # # ", + " # # "," # # "," # # "," # # "," # "," # # "," # # "," # # ", + " # # "," # # "," # # "," # "," # "," # # "," # # "," # # ", + " #### "," # # "," #### "," ### "," # "," # # "," # # "," # # # ", + " # "," # # # "," # # "," # "," # "," # # "," # # "," # # # ", + " # "," # # "," # # "," # # "," # "," # # "," # # "," ## ## ", + " # "," ## # "," # # "," ### "," # "," ### "," # "," # # ", + " "," "," "," "," "," "," "," ", + " # # "," # # "," ##### "," ##### "," "," ##### "," "," ", + " # # "," # # "," # "," ## "," # "," ## "," "," ", + " # # "," # # "," # "," ## "," # "," ## "," # "," ", + " # "," # "," # "," ## "," # "," ## "," # # "," ", + " # # "," # "," # "," ## "," # "," ## "," # # "," ", + " # # "," # "," # "," ## "," # "," ## "," "," ", + " # # "," # "," ##### "," ##### "," "," ##### "," "," ", + " "," "," "," "," "," "," "," #######", + " "," # "," # # "," # # "," # "," ## "," # "," # ", + " "," # "," # # "," # # "," #### "," ## # "," # # "," # ", + " "," # "," # # "," ##### "," # # "," # "," # # "," # ", + " "," # "," "," # # "," ### "," # "," # "," ", + " "," # "," "," ##### "," # # "," # "," # # # "," ", + " "," "," "," # # "," #### "," # ## "," # # "," ", + " "," # "," "," # # "," # "," ## "," ## # "," ", + " "," "," "," "," "," "," "," ", + " # "," # "," # "," "," "," "," "," ", + " # "," # "," # # # "," # "," "," "," "," # ", + " # "," # "," ### "," # "," "," "," "," # ", + " # "," # "," # "," ##### "," "," ##### "," "," # ", + " # "," # "," ### "," # "," # "," "," "," # ", + " # "," # "," # # # "," # "," # "," "," "," # ", + " # "," # "," # "," "," # "," "," # "," ", + " "," "," "," "," "," "," "," ", + " ### "," # "," ### "," ##### "," # "," ##### "," ### "," ##### ", + " # # "," ## "," # # "," # "," ## "," # "," # "," # ", + " # ## "," # "," # "," # "," # # "," #### "," # "," # ", + " # # # "," # "," ## "," ## "," # # "," # "," #### "," # ", + " ## # "," # "," # "," # "," ##### "," # "," # # "," # ", + " # # "," # "," # "," # # "," # "," # # "," # # "," # ", + " ### "," ### "," ##### "," ### "," # "," ### "," ### "," # ", + " "," "," "," "," "," "," "," ", + " ### "," ### "," "," "," # "," "," # "," ### ", + " # # "," # # "," "," "," # "," "," # "," # # ", + " # # "," # # "," # "," # "," # "," ##### "," # "," # ", + " ### "," #### "," "," "," # "," "," # "," # ", + " # # "," # "," # "," # "," # "," ##### "," # "," # ", + " # # "," # "," "," # "," # "," "," # "," ", + " ### "," ### "," "," # "," # "," "," # "," # ", + " "," "," "," "," "," "," "," ", + " # "," "," # "," "," # "," "," ## "," ", + " # "," "," # "," "," # "," "," # # "," ", + " # "," ### "," #### "," #### "," #### "," ### "," # "," #### ", + " "," # "," # # "," # "," # # "," # # "," #### "," # # ", + " "," #### "," # # "," # "," # # "," ##### "," # "," # # ", + " "," # # "," # # "," # "," # # "," # "," # "," #### ", + " "," #### "," #### "," #### "," #### "," #### "," # "," # ", + " "," "," "," "," "," "," "," ### ", + " # "," # "," # "," # "," ## "," "," "," ", + " # "," "," "," # "," # "," "," "," ", + " #### "," ## "," ## "," # # "," # "," ## ## "," #### "," ### ", + " # # "," # "," # "," # # "," # "," # # # "," # # "," # # ", + " # # "," # "," # "," ### "," # "," # # # "," # # "," # # ", + " # # "," # "," # "," # # "," # "," # # # "," # # "," # # ", + " # # "," ### "," # # "," # # "," ### "," # # "," # # "," ### ", + " "," "," ## "," "," "," "," "," ", + " "," "," "," "," # "," "," "," ", + " "," "," "," "," # "," "," "," ", + " #### "," #### "," # ### "," #### "," #### "," # # "," # # "," # # ", + " # # "," # # "," ## "," # "," # "," # # "," # # "," # # ", + " # # "," # # "," # "," ### "," # "," # # "," # # "," # # # ", + " #### "," #### "," # "," # "," # # "," # ## "," # # "," # # # ", + " # "," # "," # "," #### "," ## "," ## # "," # "," ## ## ", + " # "," # "," "," "," "," "," "," ", + " "," "," "," ### "," # "," ### "," ## # "," ", + " "," "," "," ## "," # "," ## "," # ## "," # # # ", + " # # "," # # "," ##### "," ## "," # "," ## "," "," # # ", + " # # "," # # "," # "," ## "," # "," ## "," "," # # # ", + " # "," # # "," # "," ## "," # "," ## "," "," # # ", + " # # "," #### "," # "," ## "," # "," ## "," "," # # # ", + " # # "," # "," ##### "," ### "," # "," ### "," "," ", + " "," ### "," "," "," # "," "," "," ", + " # "," # "," "," #######"," "," #######"," ###"," ", + " # "," # "," "," # # "," #"," ###### "," ##"," ## ", + " ## ## "," ## ## "," # "," # # "," # "," ##### #"," ######"," ### ", + " #######"," # #"," ## "," # "," # # "," ## ##"," # ## "," ", + " ###### "," # # "," ### "," # "," # # "," # # ###"," # ####"," ### ", + " ###### "," # # "," #### "," # # "," # "," ## ####"," ## "," ## ", + " ######"," # # #"," ## ## "," # # # "," # "," ## ####"," ###### "," # ", + " ## ## "," ## ## "," # #"," #######"," "," #######"," # "," ###", + " # "," "," # "," # "," #######"," #"," ###### "," ## # ", + " # "," "," # "," ### "," "," #"," ###### "," ## ", + " # "," "," # "," # # # "," "," # #"," ###### "," ### ", + " #######"," "," # "," # # #"," "," ## #"," ###### "," ######", + " # "," "," # # #"," # "," "," #######"," ###### "," ### ", + " # "," "," # # # "," # "," "," ## "," ###### "," ## ", + " # "," "," ### "," # "," "," # "," ###### "," # ", + " "," # # # "," # "," # "," "," "," ###### "," #### ##", + " # ##"," #"," #"," "," # "," # "," # # # "," # # # #", + " ## "," # #"," # #"," "," # "," # "," # # # #"," # # # ", + " ### "," # "," ### "," "," # "," # "," # # # "," # # # #", + " ###### "," #######"," ##### "," #######"," # "," #######"," # # # #"," # # # ", + " ### "," ##### "," #######"," "," # "," # "," # # # "," # # # #", + " ## "," ### "," # "," "," # "," # "," # # # #"," # # # ", + " # "," # #"," # #"," "," # "," # "," # # # "," # # # #", + " ## ####"," #"," #"," "," #######"," "," # # # #"," # # # ", + " "," "," #"," # "," #######"," # # "," #######"," # ", + " ##### "," "," #"," ### "," "," # # "," #"," # ", + " # #","####### "," #"," ##### "," "," ### ###"," #"," # ", + " # "," #"," #"," #######"," "," "," ## #"," # ", + " # "," #"," #"," ##### "," "," ### ###"," ## #"," # ", + " # "," #"," #"," ### "," "," # # "," #"," # ", + " #######","########"," #"," # "," "," # # "," #"," # ", + " "," "," #"," "," #######"," "," #######"," # ", +}; + +#define STRINGS_PER_CHAR 8 +#define CHARS_PER_ROW 8 +#define STRINGS_PER_CHAR_ROW (STRINGS_PER_CHAR * CHARS_PER_ROW) + +void make_csbits (void) { + int i,j; + int szstrs = sizeof csstrs / sizeof csstrs[0]; + int numchars = szstrs / STRINGS_PER_CHAR; + + for (i = 0; i < numchars; ++i) { + int si = ((i / STRINGS_PER_CHAR) * STRINGS_PER_CHAR_ROW) + (i % CHARS_PER_ROW); + for (j = 0; j < STRINGS_PER_CHAR; ++j) + { + const char *sp = csstrs[si]; + unsigned char cb = 0; + + si += CHARS_PER_ROW; + + while (*sp) { + if (*sp++ != ' ') cb |= 0x80; + cb >>= 1; + } + + csbits[0][i][j] = cb; + } + } + + /* move mousetext */ + for (i = 96; i < 128; ++i) + for (j = 0; j < 8; ++j) + csbits[1][i-32][j] = csbits[0][i][j]; + + /* move lowercase */ + for (i = 64; i < 96; ++i) + for (j = 0; j < 8; ++j) + csbits[1][i+32][j] = csbits[1][i+160][j] = + csbits[0][i+160][j] = csbits[0][i][j]; + + /* move numbers */ + for (i = 32; i < 64; ++i) + for (j = 0; j < 8; ++j) + csbits[1][i][j] = csbits[1][i+128][j] = + csbits[0][i+64][j] = csbits[0][i+128][j] = csbits[0][i][j]; + + /* move uppercase */ + for (i = 0; i < 32; ++i) + for (j = 0; j < 8; ++j) + csbits[1][i][j] = csbits[1][i+128][j] = csbits[1][i+192][j] = + csbits[0][i+64][j] = csbits[0][i+128][j] = csbits[0][i+192][j] = csbits[0][i][j]; + + /* invert (skip mousetext) */ + for (i = 0; i < 128; ++i) + for (j = 0; j < 8; ++j) + { + csbits[0][i][j] ^= 0xFF; + if (i < 64 || i >= 96) + csbits[1][i][j] ^= 0xFF; + } +} diff --git a/source/NTSC_CharSet.h b/source/NTSC_CharSet.h new file mode 100644 index 00000000..97ec761d --- /dev/null +++ b/source/NTSC_CharSet.h @@ -0,0 +1,27 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 2010-2011, William S Simms + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef INCLUDED_CS_H +#define INCLUDED_CS_H + +extern unsigned char csbits[2][256][8]; +void make_csbits (void); + +#endif From 2dedaf01586a461bdac0eb908017ecc716fc6ad5 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 31 Dec 2014 17:15:36 -0800 Subject: [PATCH 003/121] NTSC: fix Debugger View Output commands: TEXT, HGR, etc --- source/Applewin.cpp | 2 +- source/Debugger/Debug.cpp | 55 +++++----- source/Frame.cpp | 3 +- source/Video.cpp | 216 ++++---------------------------------- source/Video.h | 8 +- 5 files changed, 55 insertions(+), 229 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 6e80f7cd..4348e7e5 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -230,7 +230,7 @@ void ContinueExecution(void) if (g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; - VideoEndOfVideoFrame(); + VideoEndOfVideoFrame(); // NTSC currently requires this ... need to investigate why MB_EndOfVideoFrame(); } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index cde48207..4a183ceb 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4215,7 +4215,7 @@ Update_t CmdMemoryLoad (int nArgs) { bBankSpecified = false; } - +// TODO: check if extension ".hgr", ".hgr2", ".dhgr", ".dhgr2" if (g_aArgs[ iArgComma1 ].eToken != TOKEN_COMMA) return Help_Arg_1( CMD_MEMORY_LOAD ); @@ -6031,19 +6031,20 @@ enum ViewVideoPage_t Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ); -Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ) +Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags ) { VideoSetForceFullRedraw(); - _Video_Dirty(); + switch( iPage ) { - case VIEW_PAGE_X: _Video_SetupBanks( VideoGetSWPAGE2() ); break; // Page Current - case VIEW_PAGE_1: _Video_SetupBanks( false ); break; // Page 1 - case VIEW_PAGE_2: _Video_SetupBanks( true ); break; // Page 2 ! + case VIEW_PAGE_X: bVideoModeFlags |= _Video_SetupBanks( VideoGetSWPAGE2() ); break; // Page Current + case VIEW_PAGE_1: bVideoModeFlags |= _Video_SetupBanks( false ); break; // Page 1 + case VIEW_PAGE_2: bVideoModeFlags |= _Video_SetupBanks( true ); break; // Page 2 ! default: break; } - _Video_RedrawScreen( pfUpdate ); + + VideoRefreshScreen( bVideoModeFlags ); g_bDebuggerViewingAppleOutput = true; return UPDATE_NOTHING; // intentional } @@ -6051,80 +6052,80 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ) // Text 40 Update_t CmdViewOutput_Text4X (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, Update40ColCell ); + return _ViewOutput( VIEW_PAGE_X, VF_TEXT ); } Update_t CmdViewOutput_Text41 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, Update40ColCell ); + return _ViewOutput( VIEW_PAGE_1, VF_TEXT ); } Update_t CmdViewOutput_Text42 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, Update40ColCell ); + return _ViewOutput( VIEW_PAGE_2, VF_TEXT ); } // Text 80 Update_t CmdViewOutput_Text8X (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, Update80ColCell ); + return _ViewOutput( VIEW_PAGE_X, VF_TEXT | VF_80COL ); } Update_t CmdViewOutput_Text81 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, Update80ColCell ); + return _ViewOutput( VIEW_PAGE_1, VF_TEXT | VF_80COL ); } Update_t CmdViewOutput_Text82 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, Update80ColCell ); + return _ViewOutput( VIEW_PAGE_2, VF_TEXT | VF_80COL ); } // Lo-Res Update_t CmdViewOutput_GRX (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, UpdateLoResCell ); + return _ViewOutput( VIEW_PAGE_X, 0 ); } Update_t CmdViewOutput_GR1 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, UpdateLoResCell ); + return _ViewOutput( VIEW_PAGE_1, 0 ); } Update_t CmdViewOutput_GR2 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, UpdateLoResCell ); + return _ViewOutput( VIEW_PAGE_2, 0 ); } // Double Lo-Res Update_t CmdViewOutput_DGRX (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, UpdateDLoResCell ); + return _ViewOutput( VIEW_PAGE_X, VF_DHIRES | VF_80COL ); } Update_t CmdViewOutput_DGR1 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, UpdateDLoResCell ); + return _ViewOutput( VIEW_PAGE_1, VF_DHIRES | VF_80COL ); } Update_t CmdViewOutput_DGR2 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, UpdateDLoResCell ); + return _ViewOutput( VIEW_PAGE_2, VF_DHIRES | VF_80COL ); } // Hi-Res Update_t CmdViewOutput_HGRX (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, UpdateHiResCell ); + return _ViewOutput( VIEW_PAGE_X, VF_HIRES ); } Update_t CmdViewOutput_HGR1 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, UpdateHiResCell ); + return _ViewOutput( VIEW_PAGE_1, VF_HIRES ); } Update_t CmdViewOutput_HGR2 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, UpdateHiResCell ); + return _ViewOutput( VIEW_PAGE_2, VF_HIRES ); } // Double Hi-Res Update_t CmdViewOutput_DHGRX (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, UpdateDHiResCell ); + return _ViewOutput( VIEW_PAGE_X, VF_HIRES | VF_DHIRES ); } Update_t CmdViewOutput_DHGR1 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, UpdateDHiResCell ); + return _ViewOutput( VIEW_PAGE_1, VF_HIRES | VF_DHIRES ); } Update_t CmdViewOutput_DHGR2 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, UpdateDHiResCell ); + return _ViewOutput( VIEW_PAGE_2, VF_HIRES | VF_DHIRES ); } // Watches ________________________________________________________________________________________ @@ -7783,8 +7784,8 @@ void DebugContinueStepping () { if (nStepsTaken == 0x10000) // HACK_MAGIC_NUM VideoRedrawScreen(); - else - VideoRefreshScreen(); +// else +// VideoRefreshScreen(); } } else diff --git a/source/Frame.cpp b/source/Frame.cpp index e4960e9b..ad696605 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -564,7 +564,8 @@ static void DrawFrameWindow () DebugDisplay(1); else // Win7: In fullscreen mode with 1 redraw, the the screen doesn't get redraw. - VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) + //VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) + VideoRedrawScreen(); // DD Full-Screen Palette: BUGFIX: needs to come _after_ all drawing... if (g_bPaintingWindow) diff --git a/source/Video.cpp b/source/Video.cpp index 7806432c..82a37383 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -2074,7 +2074,7 @@ void VideoBenchmark () { FillMemory(mem+0x400,0x400,0x14); else CopyMemory(mem+0x400,mem+((cycle & 2) ? 0x4000 : 0x6000),0x400); - VideoRefreshScreen(); + VideoRedrawScreen(); // VideoRefreshScreen(); if (cycle++ >= 3) cycle = 0; totaltextfps++; @@ -2096,7 +2096,7 @@ void VideoBenchmark () { FillMemory(mem+0x2000,0x2000,0x14); else CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); - VideoRefreshScreen(); + VideoRedrawScreen(); // VideoRefreshScreen(); if (cycle++ >= 3) cycle = 0; totalhiresfps++; @@ -2187,7 +2187,7 @@ void VideoBenchmark () { FillMemory(mem+0x2000,0x2000,0xAA); else CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); - VideoRefreshScreen(); + VideoRedrawScreen(); // VideoRefreshScreen(); if (cycle++ >= 3) cycle = 0; realisticfps++; @@ -2499,17 +2499,10 @@ void VideoRealizePalette(HDC dc) //=========================================================================== -// Called by DrawFrameWindow() when in fullscreen mode (eg. after WM_PAINT msg) -VideoUpdateFuncPtr_t VideoRedrawScreen (UINT n) -{ - g_VideoForceFullRedraw = n; - return VideoRefreshScreen(); -} - -VideoUpdateFuncPtr_t VideoRedrawScreen () +void VideoRedrawScreen () { g_VideoForceFullRedraw = 1; - return VideoRefreshScreen(); + VideoRefreshScreen( g_uVideoMode ); } //=========================================================================== @@ -2519,12 +2512,14 @@ void _Video_Dirty() } //=========================================================================== -void _Video_SetupBanks( bool bBank2 ) +int _Video_SetupBanks( bool bBank2 ) { g_pHiresBank1 = MemGetAuxPtr (0x2000 << (int)bBank2); g_pHiresBank0 = MemGetMainPtr(0x2000 << (int)bBank2); g_pTextBank1 = MemGetAuxPtr (0x400 << (int)bBank2); g_pTextBank0 = MemGetMainPtr(0x400 << (int)bBank2); + + return bBank2 ? VF_PAGE2 : 0; } //=========================================================================== @@ -2551,12 +2546,15 @@ static void DebugRefresh(char uDebugFlag) } #endif -VideoUpdateFuncPtr_t VideoRefreshScreen () +void VideoRefreshScreen ( int bVideoModeFlags ) { #if defined(_DEBUG) && defined(DEBUG_REFRESH_TIMINGS) DebugRefresh(0); #endif + NTSC_SetVideoMode( bVideoModeFlags ); + g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + // NTSC_BEGIN: wsVideoRefresh() LPBYTE pDstFrameBufferBits = 0; LONG pitch = 0; @@ -2568,189 +2566,16 @@ VideoUpdateFuncPtr_t VideoRefreshScreen () StretchBlt(hFrameDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,g_hDeviceDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,SRCCOPY); GdiFlush(); } - return NULL; + + if (g_VideoForceFullRedraw) + --g_VideoForceFullRedraw; // NTSC_END - - // CHECK EACH CELL FOR CHANGED BYTES. REDRAW PIXELS FOR THE CHANGED BYTES - // IN THE FRAME BUFFER. MARK CELLS IN WHICH REDRAWING HAS TAKEN PLACE AS - // DIRTY. - _Video_Dirty(); - _Video_SetupBanks( SW_PAGE2 != 0 ); - - VideoUpdateFuncPtr_t pfUpdate = SW_TEXT - ? SW_80COL - ? Update80ColCell - : Update40ColCell - : SW_HIRES - ? (SW_DHIRES && SW_80COL) - ? UpdateDHiResCell - : UpdateHiResCell - : (SW_DHIRES && SW_80COL) - ? UpdateDLoResCell - : UpdateLoResCell; - - bool bMixed = (SW_MIXED) ? true : false; - _Video_RedrawScreen( pfUpdate, bMixed ); - - //g_VideoForceFullRedraw = 0; - if (g_VideoForceFullRedraw) --g_VideoForceFullRedraw; - return pfUpdate; } //=========================================================================== -void _Video_RedrawScreen( VideoUpdateFuncPtr_t pfUpdate, bool bMixed ) -{ - LPBYTE pDstFrameBufferBits = 0; - LONG pitch = 0; - HDC hFrameDC = FrameGetVideoDC(&pDstFrameBufferBits,&pitch); - CreateFrameOffsetTable(pDstFrameBufferBits,pitch); // ptr to start of each scanline - - BOOL anydirty = 0; - int y = 0; - int ypixel = 0; - - while (y < 20) { - int offset = ((y & 7) << 7) + ((y >> 3) * 40); - int x = 0; - int xpixel = 0; - while (x < 40) { - anydirty |= celldirty[x][y] = pfUpdate(x,y,xpixel,ypixel,offset+x); - ++x; - xpixel += 14; - } - ++y; - ypixel += 16; - } - - if( bMixed ) { - pfUpdate = SW_80COL - ? Update80ColCell - : Update40ColCell; - } - - while (y < 24) { - int offset = ((y & 7) << 7) + ((y >> 3) * 40); - int x = 0; - int xpixel = 0; - while (x < 40) { - anydirty |= celldirty[x][y] = pfUpdate(x,y,xpixel,ypixel,offset+x); - ++x; - xpixel += 14; - } - ++y; - ypixel += 16; - } - - // Clear this flag after TEXT screen has been updated - g_bTextFlashFlag = false; - -#if 1 - // New simpified code: - // . Oliver Schmidt gets a flickering mouse cursor with this code - if (hFrameDC && anydirty) - { - int nViewportCX, nViewportCY; - GetViewportCXCY(nViewportCX, nViewportCY); - StretchBlt(hFrameDC, 0 ,0, nViewportCX, nViewportCY, g_hDeviceDC, 0, 0, FRAMEBUFFER_W, FRAMEBUFFER_H, SRCCOPY); - GdiFlush(); - } -#else - // Original code: - if (!hFrameDC || !anydirty) - { - FrameReleaseVideoDC(); - SetLastDrawnImage(); - g_VideoForceFullRedraw = 0; - return; - } - - // COPY DIRTY CELLS FROM THE DEVICE DEPENDENT BITMAP ONTO THE SCREEN - // IN LONG HORIZONTAL RECTANGLES - BOOL remainingdirty = 0; - y = 0; - ypixel = 0; - while (y < 24) { - int start = -1; - int startx = 0; - int x = 0; - int xpixel = 0; - while (x < 40) { - if ((x == 39) && celldirty[x][y]) - if (start >= 0) { - xpixel += 14; - celldirty[x][y] = 0; - } - else - remainingdirty = 1; - if ((start >= 0) && !celldirty[x][y]) { - if ((x - startx > 1) || ((x == 39) && (xpixel == FRAMEBUFFER_W))) { - int height = 1; - while ((y+height < 24) - && celldirty[startx][y+height] - && celldirty[x-1][y+height] - && celldirty[(startx+x-1) >> 1][y+height]) - height++; - BitBlt(hFrameDC,start,ypixel,xpixel-start,height << 4, - g_hDeviceDC,start,ypixel,SRCCOPY); - while (height--) { - int loop = startx; - while (loop < x+(xpixel == FRAMEBUFFER_W)) - celldirty[loop++][y+height] = 0; - } - start = -1; - } - else - remainingdirty = 1; - start = -1; - } - else if ((start == -1) && celldirty[x][y] && (x < 39)) { - start = xpixel; - startx = x; - } - x++; - xpixel += 14; - } - y++; - ypixel += 16; - } - - // COPY ANY REMAINING DIRTY CELLS FROM THE DEVICE DEPENDENT BITMAP - // ONTO THE SCREEN IN VERTICAL RECTANGLES - if (remainingdirty) { - int x = 0; - int xpixel = 0; - while (x < 40) { - int start = -1; - int y = 0; - int ypixel = 0; - while (y < 24) { - if ((y == 23) && celldirty[x][y]) { - if (start == -1) - start = ypixel; - ypixel += 16; - celldirty[x][y] = 0; - } - if ((start >= 0) && !celldirty[x][y]) { - BitBlt(hFrameDC,xpixel,start,14,ypixel-start, - g_hDeviceDC,xpixel,start,SRCCOPY); - start = -1; - } - else if ((start == -1) && celldirty[x][y]) - start = ypixel; - y++; - ypixel += 16; - } - x++; - xpixel += 14; - } - } - - GdiFlush(); -#endif - - FrameReleaseVideoDC(); - SetLastDrawnImage(); -} +//void _Video_RedrawScreen( VideoUpdateFuncPtr_t pfUpdate, bool bMixed ) +// FrameReleaseVideoDC(); +// SetLastDrawnImage(); //=========================================================================== void VideoReinitialize () @@ -2820,7 +2645,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) if (!g_bVideoUpdatedThisFrame) { - VideoRefreshScreen(); + VideoRedrawScreen(); // VideoRefreshScreen(); g_bVideoUpdatedThisFrame = true; } } @@ -2870,7 +2695,8 @@ void VideoEndOfVideoFrame(void) if (!g_bFullSpeed || (dwCurrTime-dwLastTime >= 100)) // FullSpeed: update every 100ms { - VideoRefreshScreen(); + // Required or else screen won't update -- Sheldon's NTSC doesn't have VideoEndOfVideoFrame -- simply calls wsVideoRefresh() + VideoRedrawScreen(); // VideoRefreshScreen(); dwLastTime = dwCurrTime; } } diff --git a/source/Video.h b/source/Video.h index 1fb3075e..c5293287 100644 --- a/source/Video.h +++ b/source/Video.h @@ -77,9 +77,8 @@ void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, void VideoDisplayLogo (); void VideoInitialize (); void VideoRealizePalette (HDC); -VideoUpdateFuncPtr_t VideoRedrawScreen (UINT); -VideoUpdateFuncPtr_t VideoRedrawScreen (); -VideoUpdateFuncPtr_t VideoRefreshScreen (); +void VideoRedrawScreen (); +void VideoRefreshScreen (int bVideoFlags ); void VideoReinitialize (); void VideoResetState (); WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); @@ -98,8 +97,7 @@ bool VideoGetSWAltCharSet(void); void VideoSetForceFullRedraw(void); void _Video_Dirty(); -void _Video_RedrawScreen( VideoUpdateFuncPtr_t update, bool bMixed = false ); -void _Video_SetupBanks( bool bBank2 ); +int _Video_SetupBanks( bool bBank2 ); bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset); bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset); bool UpdateLoResCell (int x, int y, int xpixel, int ypixel, int offset); From 784fb5c62b218129c9e3620206d58bca4f35dab8 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 31 Dec 2014 17:57:02 -0800 Subject: [PATCH 004/121] Fix F9 video mode cycling works for monochrome modes --- source/NTSC.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 7f0b4e49..2805ec97 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -711,7 +711,11 @@ void NTSC_SetVideoStyle() // (int v, int s) } break; - case VT_MONO_WHITE: //VT_MONO_MONITOR: //3: +// case VT_MONO_WHITE: //VT_MONO_MONITOR: //3: + case VT_MONO_AMBER: // RGB(0xFF,0x80,0x00) + case VT_MONO_GREEN: // RGB(0x00,0xC0,0x00) + case VT_MONO_WHITE: // RGB(0xFF,0xFF,0xFF) + case VT_MONO_HALFPIXEL_REAL: if (s) { ntscMonoPixel = ntscColorPixel = ntscMonoSinglePixel; } @@ -1094,7 +1098,8 @@ void NTSC_UpdateVideoHires40 (long ticks) unsigned char * main = MemGetMainPtr(ad); bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - if (main[0] & 0x80) bt = (bt << 1) | g_nLastColumnPixelNTSC; + if (main[0] & 0x80) + bt = (bt << 1) | g_nLastColumnPixelNTSC; VIDEO_DRAW_BITS(); } } From 1fc2c0f2b2854be04375f0e8ffb6648ba4f45769 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 31 Dec 2014 17:57:57 -0800 Subject: [PATCH 005/121] Remove most of the old unused Video rendering functions --- source/Applewin.cpp | 5 +- source/Video.cpp | 1263 +------------------------------------------ source/Video.h | 2 - 3 files changed, 5 insertions(+), 1265 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 4348e7e5..03ea0cbd 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -953,10 +953,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) DiskInitialize(); LogFileOutput("Init: DiskInitialize()\n"); - CreateColorMixMap(); // For tv emulation mode - LogFileOutput("Init: CreateColorMixMap()\n"); - - int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error + int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error if (szImageName_drive1) { nError = DoDiskInsert(DRIVE_1, szImageName_drive1); diff --git a/source/Video.cpp b/source/Video.cpp index 82a37383..043e8634 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -119,23 +119,13 @@ enum Color_Palette_Index_e , HGR_PINK // MONOCHROME - // NOTE: 50% is assumed to come after 100% luminance !!! See: V_CreateLookup_MonoHiRes() - // User customizable , MONOCHROME_CUSTOM // 100% luminance , MONOCHROME_CUSTOM_50 // 50% luminance - // Pre-set "Monochromes" , MONOCHROME_AMBER -// , MONOCHROME_AMBER_50 // BUG - something trashing our palette entry !!! , MONOCHROME_GREEN -// , MONOCHROME_GREEN_50 // BUG - something trashing our palette entry !!! - , DEBUG_COLORS_START , DEBUG_COLORS_END = DEBUG_COLORS_START + NUM_DEBUG_COLORS -// DD Full Screen Palette ?!?! -// , LOGO_COLORS_START -// , LOGO_COLORS_END = LOGO_COLORS_START + 128 - , NUM_COLOR_PALETTE // The last 10 are the DEFAULT Windows colors (as it reserves 20 colors) @@ -316,17 +306,8 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) // Prototypes (Private) _____________________________________________ - void V_CreateLookup_DoubleHires (); - void V_CreateLookup_Hires (); // Old "Full-Pixel" support only: STANDARD, TEXT_OPTIMIZED, TVEMU - void V_CreateLookup_HiResHalfPixel_Authentic (); // New "Half_Pixel" support: STANDARD, TEXT_OPTIMIZED - void V_CreateLookup_HiresHalfShiftDim(); void V_CreateLookup_Lores (); - void V_CreateLookup_Text (HDC dc); -// Monochrome Full-Pixel Support - void V_CreateLookup_MonoDoubleHiRes (); - void V_CreateLookup_MonoHiRes (); - void V_CreateLookup_MonoLoRes (); - void V_CreateLookup_MonoText (HDC dc); + // Monochrome Half-Pixel Support void V_CreateLookup_MonoHiResHalfPixel_Real (); @@ -354,77 +335,6 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) @param sy Src Y // =========================================================================== */ -static inline void CopySource8(int dx, int dy, int w, int h, int sx, int sy) -{ - LPBYTE pDst = g_aFrameBufferOffset[ dy ] + dx; - LPBYTE pSrc = g_aSourceStartofLine[ sy ] + sx; - int nBytes; - - while (h--) - { - nBytes = w; - - // If not multiple of 3 bytes, copy first 3 bytes, so the next copy is 4-byte aligned. - while (nBytes & 3) - { - --nBytes; - if (g_uHalfScanLines && !(h & 1)) - *(pDst+nBytes) = 0; // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows) - else - *(pDst+nBytes) = *(pSrc+nBytes); - } - - // Copy 4 bytes at a time - while (nBytes) - { - nBytes -= 4; - if (g_uHalfScanLines && !(h & 1)) - *(LPDWORD)(pDst+nBytes) = 0; // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows) - else - *(LPDWORD)(pDst+nBytes) = *(LPDWORD)(pSrc+nBytes); - } - - pDst -= g_nFrameBufferPitch; - pSrc -= SRCOFFS_TOTAL; - } -} - -static void CopySource(int dx, int dy, int w, int h, int sx, int sy) -{ - if (!g_bIsFullScreen || !GetFullScreen32Bit()) - { - CopySource8(dx,dy,w,h,sx,sy); - return; - } - - UINT32* pDst = (UINT32*) (g_aFrameBufferOffset[ dy ] + dx*sizeof(UINT32)); - LPBYTE pSrc = g_aSourceStartofLine[ sy ] + sx; - int nBytes; - - while (h--) - { - nBytes = w; - while (nBytes) - { - --nBytes; - if (g_uHalfScanLines && !(h & 1)) - { - // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows) - *(pDst+nBytes) = 0; - } - else - { - const RGBQUAD& rRGB = g_pFramebufferinfo->bmiColors[ *(pSrc+nBytes) ]; - const UINT32 rgb = (((UINT32)rRGB.rgbRed)<<16) | (((UINT32)rRGB.rgbGreen)<<8) | ((UINT32)rRGB.rgbBlue); - *(pDst+nBytes) = rgb; - } - } - - pDst -= g_nFrameBufferPitch / sizeof(UINT32); - pSrc -= SRCOFFS_TOTAL; - } -} - //=========================================================================== void CreateFrameOffsetTable (LPBYTE addr, LONG pitch) { @@ -490,12 +400,6 @@ int GetMonochromeIndex() //=========================================================================== void V_CreateIdentityPalette () { - if (g_hPalette) - { - DeleteObject(g_hPalette); - } - g_hPalette = (HPALETTE)0; - SETFRAMECOLOR(BLACK, 0x00,0x00,0x00); // 0 SETFRAMECOLOR(DARK_RED, 0x80,0x00,0x00); // 1 // not used SETFRAMECOLOR(DARK_GREEN, 0x00,0x80,0x00); // 2 // not used @@ -546,7 +450,6 @@ void V_CreateIdentityPalette () , ((GetBValue(monochrome)/2) & 0xFF) ); - // SEE: V_CreateLookup_MonoText SETFRAMECOLOR( MONOCHROME_AMBER , 0xFF,0x80,0x01); // Used for Monochrome Hi-Res graphics not text! SETFRAMECOLOR( MONOCHROME_GREEN , 0x00,0xC0,0x01); // Used for Monochrome Hi-Res graphics not text! // BUG PALETTE COLLAPSE: WTF?? Soon as we set 0xFF,0xFF,0xFF we lose text colors?!?! @@ -563,422 +466,9 @@ void V_CreateIdentityPalette () SETFRAMECOLOR(MAGENTA, 0xC7,0x34,0xFF); // FD Linards Tweaked 0xFF,0x00,0xFF -> 0xC7,0x34,0xFF SETFRAMECOLOR(CYAN, 0x00,0xFF,0xFF); // FE SETFRAMECOLOR(WHITE, 0xFF,0xFF,0xFF); // FF - - // IF WE ARE IN A PALETTIZED VIDEO MODE, CREATE AN IDENTITY PALETTE - HWND window = GetDesktopWindow(); - HDC dc = GetDC(window); - - // int GetDeviceCaps( HDC, nIndex ); - int colors = GetDeviceCaps(dc,SIZEPALETTE); // 16/24/32bpp = 0 - int system = GetDeviceCaps(dc,NUMCOLORS); // 16/24/32bpp = -1 +} #if 0 - // DD Full Screen Palette - // Full Screen Debug Colors - BYTE *pTmp; - - pTmp = ((BYTE*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER); - pTmp += (DEBUG_COLORS_START * 4); - Debug_UpdatePalette( pTmp ); - - // GET THE PALETTE ENTRIES OF THE LOGO - RGBQUAD aLogoPalette[256]; - ZeroMemory(aLogoPalette,sizeof(aLogoPalette)); - if (g_hLogoBitmap) - { - BYTE *pSrc = NULL; - BITMAP bmp; - PBITMAPINFO pbmi; -// WORD cClrBits; - // Retrieve the bitmap color format, width, and height. - if (GetObject(g_hLogoBitmap, sizeof(BITMAP), (LPSTR)&bmp)) - { - pSrc = (BYTE*) pbmi->bmiColors; - - // Logo uses 128 colors - pTmp = ((BYTE*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER); - pTmp += (LOGO_COLORS_START * 4); - int iPal = 0; - for( iPal = 0; iPal < 128; iPal++ ) - { - *pTmp++ = *pSrc++; - *pTmp++ = *pSrc++; - *pTmp++ = *pSrc++; - *pTmp++ = *pSrc++; - } - } - } -#endif - - int bRasterPalette = (GetDeviceCaps(dc,RASTERCAPS) & RC_PALETTE); - if (bRasterPalette && (colors <= 256)) - { - // GET THE PALETTE ENTRIES OF THE LOGO - RGBQUAD aLogoPalette[256]; - ZeroMemory(aLogoPalette,sizeof(aLogoPalette)); - if (g_hLogoBitmap) { - HDC memdc = CreateCompatibleDC(dc); - SelectObject(memdc,g_hLogoBitmap); - GetDIBColorTable(memdc,0,colors,aLogoPalette); - DeleteDC(memdc); - } - - // CREATE A PALETTE ENTRY ARRAY - LOGPALETTE *paldata = (LOGPALETTE *)VirtualAlloc( - NULL, - sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), - MEM_COMMIT, - PAGE_READWRITE - ); - - paldata->palVersion = 0x300; - paldata->palNumEntries = colors; - GetSystemPaletteEntries(dc,0,colors,paldata->palPalEntry); - - // FILL IN THE PALETTE ENTRIES - int paletteindex = 0; - int logoindex = 0; - int halftoneindex = 0; - - // COPY THE SYSTEM PALETTE ENTRIES AT THE BEGINNING OF THE PALETTE - for (; paletteindex < system/2; paletteindex++) - paldata->palPalEntry[paletteindex].peFlags = 0; - - // FILL IN THE MIDDLE PORTION OF THE PALETTE WITH OUR OWN COLORS - for (int ourindex = DEEP_RED; ourindex <= NUM_COLOR_PALETTE; ourindex++) { - paldata->palPalEntry[paletteindex].peRed = g_pFramebufferinfo->bmiColors[ourindex].rgbRed; - paldata->palPalEntry[paletteindex].peGreen = g_pFramebufferinfo->bmiColors[ourindex].rgbGreen; - paldata->palPalEntry[paletteindex].peBlue = g_pFramebufferinfo->bmiColors[ourindex].rgbBlue; - paldata->palPalEntry[paletteindex].peFlags = PC_NOCOLLAPSE; - paletteindex++; - } - - for (; paletteindex < colors-system/2; paletteindex++) { - - // IF THIS PALETTE ENTRY IS NEEDED FOR THE LOGO, COPY IN THE LOGO COLOR - if (aLogoPalette[logoindex].rgbRed && - aLogoPalette[logoindex].rgbGreen && - aLogoPalette[logoindex].rgbBlue) - { - paldata->palPalEntry[paletteindex].peRed = aLogoPalette[logoindex].rgbRed; - paldata->palPalEntry[paletteindex].peGreen = aLogoPalette[logoindex].rgbGreen; - paldata->palPalEntry[paletteindex].peBlue = aLogoPalette[logoindex].rgbBlue; - } - - // OTHERWISE, ADD A HALFTONING COLOR, SO THAT OTHER APPLICATIONS - // RUNNING IN THE BACKGROUND WILL HAVE SOME REASONABLE COLORS TO USE - else - { - static BYTE halftonetable[6] = {32,64,96,160,192,224}; - paldata->palPalEntry[paletteindex].peRed = halftonetable[halftoneindex % 6]; - paldata->palPalEntry[paletteindex].peGreen = halftonetable[halftoneindex/6 % 6]; - paldata->palPalEntry[paletteindex].peBlue = halftonetable[halftoneindex/36 % 6]; - ++halftoneindex; - } - - ++logoindex; - paldata->palPalEntry[paletteindex].peFlags = PC_NOCOLLAPSE; - } - - // COPY THE SYSTEM PALETTE ENTRIES AT THE END OF THE PALETTE - for (; paletteindex < colors; paletteindex++) - paldata->palPalEntry[paletteindex].peFlags = 0; - - // FILL THE FRAME BUFFER TABLE WITH COLORS FROM OUR PALETTE - for (int iPal = 0; iPal < colors; iPal++) { - g_pFramebufferinfo->bmiColors[ iPal ].rgbRed = paldata->palPalEntry[ iPal ].peRed; - g_pFramebufferinfo->bmiColors[ iPal ].rgbGreen = paldata->palPalEntry[ iPal ].peGreen; - g_pFramebufferinfo->bmiColors[ iPal ].rgbBlue = paldata->palPalEntry[ iPal ].peBlue; - } - - // CREATE THE PALETTE - g_hPalette = CreatePalette(paldata); - VirtualFree(paldata,0,MEM_RELEASE); - } - - ReleaseDC(window,dc); -} - -//=========================================================================== -void V_CreateDIBSections () -{ - CopyMemory(g_pSourceHeader->bmiColors,g_pFramebufferinfo->bmiColors,256*sizeof(RGBQUAD)); - - // CREATE THE DEVICE CONTEXT - HWND window = GetDesktopWindow(); - HDC dc = GetDC(window); - if (g_hDeviceDC) - { - DeleteDC(g_hDeviceDC); - } - g_hDeviceDC = CreateCompatibleDC(dc); - - // CREATE THE FRAME BUFFER DIB SECTION - if (g_hDeviceBitmap) - DeleteObject(g_hDeviceBitmap); - g_hDeviceBitmap = CreateDIBSection( - dc, - g_pFramebufferinfo, - DIB_RGB_COLORS, - (LPVOID *)&g_pFramebufferbits,0,0 - ); - SelectObject(g_hDeviceDC,g_hDeviceBitmap); - - // CREATE THE SOURCE IMAGE DIB SECTION - HDC sourcedc = CreateCompatibleDC(dc); - ReleaseDC(window,dc); - if (g_hSourceBitmap) - DeleteObject(g_hSourceBitmap); - - g_hSourceBitmap = CreateDIBSection( - sourcedc, - g_pSourceHeader, - DIB_RGB_COLORS, - (LPVOID *)&g_pSourcePixels,0,0 - ); - SelectObject(sourcedc,g_hSourceBitmap); - - // CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE SOURCE IMAGE - for (int y = 0; y < MAX_SOURCE_Y; y++) - g_aSourceStartofLine[ y ] = g_pSourcePixels + SRCOFFS_TOTAL*((MAX_SOURCE_Y-1) - y); - - // DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER - ZeroMemory(g_pSourcePixels,SRCOFFS_TOTAL*512); // 32 bytes/pixel * 16 colors = 512 bytes/row - - // First monochrome mode is seperate from others - if ((g_eVideoType >= VT_COLOR_STANDARD) && (g_eVideoType < VT_MONO_AMBER)) - { - V_CreateLookup_Text(sourcedc); - V_CreateLookup_Lores(); - - if ( g_eVideoType == VT_COLOR_TVEMU ) - V_CreateLookup_Hires(); - else -#if HALF_DIM_SUPPORT - V_CreateLookup_HiresHalfShiftDim(); -#else - V_CreateLookup_HiResHalfPixel_Authentic(); -#endif - V_CreateLookup_DoubleHires(); - } - else - { - V_CreateLookup_MonoText(sourcedc); - V_CreateLookup_MonoLoRes(); - - switch (g_eVideoType) - { - case VT_MONO_AMBER : /* intentional fall-thru */ - case VT_MONO_GREEN : /* intentional fall-thru */ - case VT_MONO_WHITE : /* intentional fall-thru */ - case VT_MONO_HALFPIXEL_REAL : V_CreateLookup_MonoHiResHalfPixel_Real() ; break; - default: V_CreateLookup_MonoHiRes(); break; - } - V_CreateLookup_MonoDoubleHiRes(); - } - DeleteDC(sourcedc); -} - -//=========================================================================== -void V_CreateLookup_DoubleHires () -{ -#define OFFSET 3 -#define SIZE 10 - - for (int column = 0; column < 256; column++) { - int coloffs = SIZE * column; - for (unsigned byteval = 0; byteval < 256; byteval++) { - int color[SIZE]; - ZeroMemory(color,sizeof(color)); - unsigned pattern = MAKEWORD(byteval,column); - int pixel; - for (pixel = 1; pixel < 15; pixel++) { - if (pattern & (1 << pixel)) { - int pixelcolor = 1 << ((pixel-OFFSET) & 3); - if ((pixel >= OFFSET+2) && (pixel < SIZE+OFFSET+2) && (pattern & (0x7 << (pixel-4)))) - color[pixel-(OFFSET+2)] |= pixelcolor; - if ((pixel >= OFFSET+1) && (pixel < SIZE+OFFSET+1) && (pattern & (0xF << (pixel-4)))) - color[pixel-(OFFSET+1)] |= pixelcolor; - if ((pixel >= OFFSET+0) && (pixel < SIZE+OFFSET+0)) - color[pixel-(OFFSET+0)] |= pixelcolor; - if ((pixel >= OFFSET-1) && (pixel < SIZE+OFFSET-1) && (pattern & (0xF << (pixel+1)))) - color[pixel-(OFFSET-1)] |= pixelcolor; - if ((pixel >= OFFSET-2) && (pixel < SIZE+OFFSET-2) && (pattern & (0x7 << (pixel+2)))) - color[pixel-(OFFSET-2)] |= pixelcolor; - } - } - - if (g_eVideoType == VT_COLOR_TEXT_OPTIMIZED) - { - // Activate for fringe reduction on white HGR text - drawback: loss of color mix patterns in HGR Video Mode. - for (pixel = 0; pixel < 13; pixel++) - { - if ((pattern & (0xF << pixel)) == (unsigned)(0xF << pixel)) - for (int pos = pixel; pos < pixel + 4; pos++) - if (pos >= OFFSET && pos < SIZE+OFFSET) - color[pos-OFFSET] = 15; - } - } - - int y = byteval << 1; - for (int x = 0; x < SIZE; x++) { - SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y ,DoubleHiresPalIndex[ color[x] ]); - SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y+1,DoubleHiresPalIndex[ color[x] ]); - } - } - } -#undef SIZE -#undef OFFSET -} - -//=========================================================================== -void V_CreateLookup_Hires () -{ - int iMonochrome = GetMonochromeIndex(); - - // BYTE colorval[6] = {MAGENTA,BLUE,GREEN,ORANGE,BLACK,WHITE}; - // BYTE colorval[6] = {HGR_VIOLET,HGR_BLUE,HGR_GREEN,HGR_ORANGE,HGR_BLACK,HGR_WHITE}; - for (int iColumn = 0; iColumn < 16; iColumn++) - { - int coloffs = iColumn << 5; - - for (unsigned iByte = 0; iByte < 256; iByte++) - { - int aPixels[11]; - - aPixels[ 0] = iColumn & 4; - aPixels[ 1] = iColumn & 8; - aPixels[ 9] = iColumn & 1; - aPixels[10] = iColumn & 2; - - int nBitMask = 1; - int iPixel; - for (iPixel = 2; iPixel < 9; iPixel++) { - aPixels[iPixel] = ((iByte & nBitMask) != 0); - nBitMask <<= 1; - } - - int hibit = ((iByte & 0x80) != 0); - int x = 0; - int y = iByte << 1; - - while (x < 28) - { - int adj = (x >= 14) << 1; - int odd = (x >= 14); - - for (iPixel = 2; iPixel < 9; iPixel++) - { - int color = CM_Black; - if (aPixels[iPixel]) - { - if (aPixels[iPixel-1] || aPixels[iPixel+1]) - color = CM_White; - else - color = ((odd ^ (iPixel&1)) << 1) | hibit; - } - else if (aPixels[iPixel-1] && aPixels[iPixel+1]) - { - // Activate fringe reduction on white HGR text - drawback: loss of color mix patterns in HGR video mode. - // VT_COLOR_STANDARD = Fill in colors in between white pixels - // VT_COLOR_TVEMU = Fill in colors in between white pixels (Post Processing will mix/merge colors) - // VT_COLOR_TEXT_OPTIMIZED --> !(aPixels[iPixel-2] && aPixels[iPixel+2]) = Don't fill in colors in between white - if ((g_eVideoType == VT_COLOR_TVEMU) || !(aPixels[iPixel-2] && aPixels[iPixel+2]) ) - color = ((odd ^ !(iPixel&1)) << 1) | hibit; // No white HGR text optimization - } - - //if (g_eVideoType == VT_MONO_AUTHENTIC) { - // int nMonoColor = (color != CM_Black) ? iMonochrome : BLACK; - // SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , nMonoColor); // buggy - // SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , nMonoColor); // buggy - // SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1,BLACK); // BL - // SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1,BLACK); // BR - //} else - { - // Colors - Top/Bottom Left/Right - // cTL cTR - // cBL cBR - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y ,HiresToPalIndex[color]); // cTL - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y ,HiresToPalIndex[color]); // cTR - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1,HiresToPalIndex[color]); // cBL - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1,HiresToPalIndex[color]); // cBR - } - x += 2; - } - } - } - } -} - - -//=========================================================================== -void V_CreateLookup_Lores () -{ - for (int color = 0; color < 16; color++) - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) - SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,LoresResColors[color]); -} - - -//=========================================================================== -void V_CreateLookup_MonoDoubleHiRes () -{ - int iMonochrome = GetMonochromeIndex(); - - for (int column = 0; column < 256; column++) - { - int coloffs = 10 * column; - for (unsigned byteval = 0; byteval < 256; byteval++) - { - unsigned pattern = MAKEWORD(byteval,column); - int y = byteval << 1; - for (int x = 0; x < 10; x++) - { - BYTE colorval = pattern & (1 << (x+3)) ? iMonochrome : BLACK; - -#if 0 - if (g_eVideoType == VT_MONO_AUTHENTIC) - { - SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y ,colorval); - SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y+1,BLACK); - } - else -#endif - { - SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y ,colorval); - SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y+1,colorval); - } - } - } - } -} - -//=========================================================================== -void V_CreateLookup_MonoHiRes () -{ - const int iMonochrome = GetMonochromeIndex(); - - for (int column = 0; column < 512; column += 16) - { - for (int y = 0; y < 512; y += 2) // optimization: Byte=0..FF, Row=Byte*2 - { - unsigned val = (y >> 1); // iByte = (y / 2) - for (int x = 0; x < 16; x += 2) // 8 pixels - { - BYTE colorval = (val & 1) ? iMonochrome : BLACK; - val >>= 1; - SETSOURCEPIXEL(SRCOFFS_HIRES+column+x ,y ,colorval); - SETSOURCEPIXEL(SRCOFFS_HIRES+column+x+1,y ,colorval); - { - SETSOURCEPIXEL(SRCOFFS_HIRES+column+x ,y+1,colorval); - SETSOURCEPIXEL(SRCOFFS_HIRES+column+x+1,y+1,colorval); - } - } - } - } -} - //=========================================================================== void V_CreateLookup_HiResHalfPixel_Authentic () // Colors are solid (100% coverage) { @@ -1043,26 +533,7 @@ Legend: // Fixup missing pixels that normally have been scan-line shifted -- Apple "half-pixel" -- but cross 14-pixel boundaries. if( hibit ) { - if ( aPixels[1] ) // preceeding pixel on? -#if 0 // Optimization: Doesn't seem to matter if we ignore the 2 pixels of the next byte - for (iPixel = 0; iPixel < 9; iPixel++) // NOTE: You MUST start with the preceding 2 pixels !!! - if (aPixels[iPixel]) // pixel on -#endif - { - if (aPixels[2] || aPixels[0]) // White if pixel from previous byte and first pixel of this byte is on - { - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_WHITE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_WHITE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_WHITE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_WHITE ); - } else { // Optimization: odd = (iPixel & 1); if (!odd) case is same as if(odd) !!! // Reference: Gumball - Gumball Machine - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_ORANGE ); // left half of orange pixels - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_ORANGE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_BLUE ); // right half of blue pixels 4, 11, 18, ... - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_BLUE ); - } - } -#if HALF_PIXEL_SOLID + // Test Patterns // 81 blue // 2000:D5 AA D5 AA -> 2001:AA D5 should not have black gap, should be blue @@ -1076,8 +547,6 @@ Legend: // 29D0:C0 90 88 -> Blue black orange // Game: Ultima 4 -- Ultima 4 Logo - bottom half of screen has a "mini-game" / demo -- far right has tree and blue border // 2176:2A AB green black_gap white blue_border // Should have black gap between green and white - else if ( aPixels[0] ) // prev prev pixel on - { // Game: Gumball // 218E:AA 97 => 2000: A9 87 orange_white // Should have no gap between orange and white // 229A:AB A9 87 -> 2000: 00 A9 87 white orange black blue_white // Should have no gap between blue and white @@ -1092,134 +561,20 @@ Legend: if ( aPixels[2] ) #if HALF_PIXEL_BLEED // No Half-Pixel Bleed - if ( aPixels[3] ) { SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , DARK_BLUE ); // Gumball: 229A: AB A9 87 - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, DARK_BLUE ); SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , BROWN ); // half luminance red Elite: 2444: BB F7 SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, BROWN ); // half luminance red Gumball: 218E: AA 97 - } else { SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5 - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_BLUE ); SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5 - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_ORANGE ); - } #else - if ((g_eVideoType == VT_COLOR_STANDARD) || ( !aPixels[3] )) - { // "Text optimized" IF this pixel on, and adjacent right pixel off, then colorize first half-pixel of this byte +// "Text optimized" IF this pixel on, and adjacent right pixel off, then colorize first half-pixel of this byte SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5 - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_BLUE ); SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5 - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_ORANGE ); - } #endif // HALF_PIXEL_BLEED - } -#endif // HALF_PIXEL_SOLID - } - x += hibit; - - while (x < 28) - { - int adj = (x >= 14) << 1; // Adjust start of 7 last pixels to be 16-byte aligned! - int odd = (x >= 14); - for (iPixel = 2; iPixel < 9; iPixel++) - { - int color = CM_Black; - if (aPixels[iPixel]) // pixel on - { - color = CM_White; - if (aPixels[iPixel-1] || aPixels[iPixel+1]) // adjacent pixels are always white - color = CM_White; - else - color = ((odd ^ (iPixel&1)) << 1) | hibit; // map raw color to our hi-res colors - } -#if HALF_PIXEL_SOLID - else if (aPixels[iPixel-1] && aPixels[iPixel+1]) // IF prev_pixel && next_pixel THEN - { - // Activate fringe reduction on white HGR text - drawback: loss of color mix patterns in HGR video mode. - if ( - (g_eVideoType == VT_COLOR_STANDARD) // Fill in colors in between white pixels - || (g_eVideoType == VT_COLOR_TVEMU) // Fill in colors in between white pixels (Post Processing will mix/merge colors) - || !(aPixels[iPixel-2] && aPixels[iPixel+2]) ) // VT_COLOR_TEXT_OPTIMIZED -> Don't fill in colors in between white - { // Test Pattern: Ultima 4 Logo - Castle // 3AC8: 36 5B 6D 36 - color = ((odd ^ !(iPixel&1)) << 1) | hibit; // No white HGR text optimization - } - } -#endif - // Colors - Top/Bottom Left/Right - // cTL cTR - // cBL cBR - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj ,y ,HiresToPalIndex[color]); // cTL - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj+1,y ,HiresToPalIndex[color]); // cTR - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj ,y+1,HiresToPalIndex[color]); // cBL - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj+1,y+1,HiresToPalIndex[color]); // cBR - x += 2; - } - } - } - } } -//=========================================================================== -void V_CreateLookup_HiresHalfShiftDim () -{ - // BYTE colorval[6] = {HGR_MAGENTA,HGR_BLUE,HGR_GREEN,HGR_RED,HGR_BLACK,HGR_WHITE}; - for (int iColumn = 0; iColumn < 16; iColumn++) - { - int coloffs = iColumn << 5; - - for (unsigned iByte = 0; iByte < 256; iByte++) - { - int aPixels[11]; - - aPixels[ 0] = iColumn & 4; - aPixels[ 1] = iColumn & 8; - aPixels[ 9] = iColumn & 1; - aPixels[10] = iColumn & 2; - - int nBitMask = 1; - int iPixel; - for (iPixel = 2; iPixel < 9; iPixel++) { - aPixels[iPixel] = ((iByte & nBitMask) != 0); - nBitMask <<= 1; - } - - int hibit = ((iByte & 0x80) != 0); - int x = 0; - int y = iByte << 1; - - while (x < 28) - { - int adj = (x >= 14) << 1; - int odd = (x >= 14); - - for (iPixel = 2; iPixel < 9; iPixel++) - { - int color = CM_Black; - if (aPixels[iPixel]) - { - if (aPixels[iPixel-1] || aPixels[iPixel+1]) - { - color = CM_White; - } - else - color = ((odd ^ (iPixel&1)) << 1) | hibit; - } - else if (aPixels[iPixel-1] && aPixels[iPixel+1]) - { - /* - activate for fringe reduction on white hgr text - - drawback: loss of color mix patterns in HGR mode. - select g_eVideoType by index exclusion - */ - if ( - (g_eVideoType == VT_COLOR_STANDARD) // Fill in colors in between white pixels - || (g_eVideoType == VT_COLOR_TVEMU) // Fill in colors in between white pixels (Post Processing will mix/merge colors) - || !(aPixels[iPixel-2] && aPixels[iPixel+2]) ) // VT_COLOR_TEXT_OPTIMIZED -> Don't fill in colors in between white - color = ((odd ^ !(iPixel&1)) << 1) | hibit; - } - /* Address Binary -> Displayed 2000:01 0---0001 -> 1 0 0 0 column 1 @@ -1237,120 +592,8 @@ void V_CreateLookup_HiresHalfShiftDim () @reference: see Beagle Bro's Disk: "Silicon Salad", File: DOUBLE HI-RES Fortunately double-hires is supported via pixel doubling, so we can do half-pixel shifts ;-) */ - switch (color) - { - case CM_Violet: - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_VIOLET ); // HiresToPalIndex - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , DARK_MAGENTA ); // HiresDimmedIndex - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_VIOLET ); // HiresToPalIndex - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, DARK_MAGENTA ); // HiresDimmedIndex - break; - - case CM_Blue : - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_BLUE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y , DARK_BLUE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_BLUE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y+1, DARK_BLUE ); - // Prevent column gaps - if (hibit) - { - if (iPixel <= 2) - { - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , DARK_BLUE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, DARK_BLUE ); - } - } - break; - - case CM_Green : - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_GREEN ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , DARK_GREEN ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_GREEN ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, DARK_GREEN ); - break; - - case CM_Orange: - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_ORANGE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y , BROWN ); // DARK_RED is a bit "too" red - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_ORANGE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y+1, BROWN ); // DARK_RED is a bit "too" red - // Prevent column gaps - if (hibit) - { - if (iPixel <= 2) - { - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , BROWN ); // DARK_RED is a bit "too" red - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, BROWN ); // DARK_RED is a bit "too" red - } - } - break; - - case CM_Black : - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_BLACK ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_BLACK ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_BLACK ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_BLACK ); - break; - - case CM_White : - // Don't dither / half-shift white, since DROL cutscene looks bad :( - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_WHITE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_WHITE ); - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_WHITE ); // LIGHT_GRAY <- for that half scan-line look - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_WHITE ); // LIGHT_GRAY <- for that half scan-line look - // Prevent column gaps - if (hibit) - { - if (iPixel <= 2) - { - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_WHITE ); // LIGHT_GRAY HGR_GREY1 - SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_WHITE ); // LIGHT_GRAY HGR_GREY1 - } - } - break; - default: - break; - } - x += 2; - } - } - } - } -} - -//=========================================================================== -void V_CreateLookup_MonoHiResHalfPixel_Real () -{ - int iMono = GetMonochromeIndex(); - - for (int iColumn = 0; iColumn < 16; iColumn++) - { - int offset = iColumn << 5; // every column is 32 bytes wide - - for (unsigned iByte = 0; iByte < 256; iByte++) - { - int aPixels[11]; // c2 c1 b7 b6 b5 b4 b3 b2 b1 b0 c8 c4 - - aPixels[ 0] = iColumn & 4; - aPixels[ 1] = iColumn & 8; - aPixels[ 9] = iColumn & 1; - aPixels[10] = iColumn & 2; - - int nBitMask = 1; - int iPixel; - for (iPixel = 2; iPixel < 9; iPixel++) - { - aPixels[iPixel] = ((iByte & nBitMask) != 0); - nBitMask <<= 1; - } - - int hibit = (iByte >> 7) & 1; // ((iByte & 0x80) != 0); - int x = 0; - int y = iByte << 1; // Fixup missing pixels that normally have been scan-line shifted -- Apple "half-pixel" -- but cross 14-pixel boundaries. - if( hibit ) - { /* Test Cases // Games Archon Logo @@ -1365,66 +608,7 @@ void V_CreateLookup_MonoHiResHalfPixel_Real () 2000:D0 80 00 2800:80 D0 00 */ - if ( aPixels[1] ) // preceeding pixel on? - { - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x ,y ,iMono); // first 7 HGR_BLUE - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x ,y+1,iMono); // first 7 - - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y ,iMono); // second 7 HGR_ORANGE - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y+1,iMono); // second 7 - } - } - - while (x < 28) - { - int adj = (x >= 14) << 1; // Adjust start of 7 last pixels to be 16-byte aligned! - int odd = (x >= 14); - - for (iPixel = 2; iPixel < 9; iPixel++) - { - int color = aPixels[iPixel] ? iMono : HGR_BLACK; - - // Colors - Top/Bottom Left/Right - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj +hibit,y ,color); // TL - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj+1+hibit,y ,color); // BL - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj +hibit,y+1,color); // BL - SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj+1+hibit,y+1,color); // BR - x += 2; - } - } - } - } -} - -//=========================================================================== -void V_CreateLookup_MonoLoRes () { - int iMonochrome = GetMonochromeIndex(); - - for (int color = 0; color < 16; color++) - { - for (int x = 0; x < 16; x++) - { - for (int y = 0; y < 16; y++) - { - BYTE colorval = (color >> (x & 3) & 1) ? iMonochrome : BLACK; -#if 0 - if (g_eVideoType == VT_MONO_AUTHENTIC) - { - if (y & 1) - SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,BLACK); - else - SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,colorval); - } - else #endif - { - SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,colorval); - } - } - } - } -} - // google: CreateDIBPatternBrushPt // http://209.85.141.104/search?q=cache:mB3htrQGW8kJ:bookfire.net/wince/wince-programming-ms-press2/source/prowice/ch02e.htm @@ -1510,32 +694,6 @@ static void CreateLookup_TextCommon(HDC hDstDC, DWORD rop) DeleteObject(hCharBitmap[i]); } -static void V_CreateLookup_Text(HDC hDstDC) -{ - CreateLookup_TextCommon(hDstDC, SRCCOPY); -} - -static void V_CreateLookup_MonoText(HDC hDstDC) -{ - HBRUSH hBrush; - switch (g_eVideoType) - { - case VT_MONO_AMBER: hBrush = CreateSolidBrush(RGB(0xFF,0x80,0x00)); break; - case VT_MONO_GREEN: hBrush = CreateSolidBrush(RGB(0x00,0xC0,0x00)); break; - case VT_MONO_WHITE: hBrush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); break; - default : hBrush = CreateSolidBrush(monochrome); break; - } - - SelectObject(hDstDC, hBrush); - - // NB. MERGECOPY (not SRCCOPY) to merge the src with the colour of the dst's selected brush - CreateLookup_TextCommon(hDstDC, MERGECOPY); - - SelectObject(hDstDC,GetStockObject(NULL_BRUSH)); - DeleteObject(hBrush); -} - - //=========================================================================== void SetLastDrawnImage () { @@ -1563,127 +721,6 @@ static inline int GetOriginal2EOffset(BYTE ch) return !IsOriginal2E() || !g_nAltCharSetOffset || (ch<0x40) || (ch>0x5F) ? 0 : -g_nAltCharSetOffset; } -bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset) -{ - BYTE ch = *(g_pTextBank0+offset); - bool bCharChanged = (ch != *(vidlastmem+offset+0x400) || g_VideoForceFullRedraw); - - // FLASHing chars: - // - FLASHing if:Alt Char Set is OFF && 0x40<=char<=0x7F - // - The inverse of this char is located at: char+0x40 - bool bCharFlashing = (g_nAltCharSetOffset == 0) && (ch >= 0x40) && (ch <= 0x7F); - - if(bCharChanged || (bCharFlashing && g_bTextFlashFlag)) - { - bool bInvert = bCharFlashing ? g_bTextFlashState : false; - - CopySource(xpixel,ypixel, - APPLE_FONT_WIDTH, APPLE_FONT_HEIGHT, - (IS_APPLE2 ? SRCOFFS_IIPLUS : SRCOFFS_40COL) + ((ch & 0x0F) << 4), - (ch & 0xF0) + g_nAltCharSetOffset + GetOriginal2EOffset(ch) + (bInvert ? 0x40 : 0x00)); - - return true; - } - - return false; -} - -inline bool _Update80ColumnCell( BYTE c, const int xPixel, const int yPixel, bool bCharFlashing ) -{ - bool bInvert = bCharFlashing ? g_bTextFlashState : false; - - CopySource( - xPixel, yPixel, - (APPLE_FONT_WIDTH / 2), APPLE_FONT_HEIGHT, - SRCOFFS_80COL + ((c & 0x0F) << 3), - (c & 0xF0) + g_nAltCharSetOffset + GetOriginal2EOffset(c) + (bInvert ? 0x40 : 0x00)); - - return true; -} - -//=========================================================================== -bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset) -{ - bool bDirty = false; - -#if FLASH_80_COL - BYTE c1 = *(g_pTextBank1 + offset); // aux - BYTE c0 = *(g_pTextBank0 + offset); // main - - bool bC1Changed = (c1 != *(vidlastmem + offset + 0) || g_VideoForceFullRedraw); - bool bC0Changed = (c0 != *(vidlastmem + offset + 0x400) || g_VideoForceFullRedraw); - - bool bC1Flashing = (g_nAltCharSetOffset == 0) && (c1 >= 0x40) && (c1 <= 0x7F); - bool bC0Flashing = (g_nAltCharSetOffset == 0) && (c0 >= 0x40) && (c0 <= 0x7F); - - if (bC1Changed || (bC1Flashing && g_bTextFlashFlag)) - bDirty = _Update80ColumnCell( c1, xpixel, ypixel, bC1Flashing ); - - if (bC0Changed || (bC0Flashing && g_bTextFlashFlag)) - bDirty |= _Update80ColumnCell( c0, xpixel + 7, ypixel, bC0Flashing ); - -#else - BYTE auxval = *(g_pTextBank1 + offset); // aux - BYTE mainval = *(g_pTextBank0 + offset); // main - - if ((auxval != *(vidlastmem+offset)) || - (mainval != *(vidlastmem+offset+0x400)) || - g_VideoForceFullRedraw) - { - CopySource(xpixel,ypixel, - (APPLE_FONT_WIDTH / 2), APPLE_FONT_HEIGHT, - SRCOFFS_80COL + ((auxval & 15)<<3), - ((auxval>>4)<<4) + g_nAltCharSetOffset); - - CopySource(xpixel+7,ypixel, - (APPLE_FONT_WIDTH / 2), APPLE_FONT_HEIGHT, - SRCOFFS_80COL + ((mainval & 15)<<3), - ((mainval>>4)<<4) + g_nAltCharSetOffset ); - - bDirty = true; - } -#endif - - return bDirty; -} - -//=========================================================================== -bool UpdateDHiResCell (int x, int y, int xpixel, int ypixel, int offset) -{ - bool bDirty = false; - int yoffset = 0; - while (yoffset < 0x2000) { - BYTE byteval1 = (x > 0) ? *(g_pHiresBank0+offset+yoffset-1) : 0; - BYTE byteval2 = *(g_pHiresBank1 +offset+yoffset); - BYTE byteval3 = *(g_pHiresBank0+offset+yoffset); - BYTE byteval4 = (x < 39) ? *(g_pHiresBank1 +offset+yoffset+1) : 0; - if ((byteval2 != *(vidlastmem+offset+yoffset)) || - (byteval3 != *(vidlastmem+offset+yoffset+0x2000)) || - ((x > 0) && ((byteval1 & 0x70) != (*(vidlastmem+offset+yoffset+0x1FFF) & 0x70))) || - ((x < 39) && ((byteval4 & 0x07) != (*(vidlastmem+offset+yoffset+ 1) & 0x07))) || - g_VideoForceFullRedraw) { - DWORD dwordval = (byteval1 & 0x70) | ((byteval2 & 0x7F) << 7) | - ((byteval3 & 0x7F) << 14) | ((byteval4 & 0x07) << 21); -#define PIXEL 0 -#define COLOR ((xpixel + PIXEL) & 3) -#define VALUE (dwordval >> (4 + PIXEL - COLOR)) - CopySource(xpixel+PIXEL,ypixel+(yoffset >> 9),7,2, - SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR,LOBYTE(VALUE)<<1); -#undef PIXEL -#define PIXEL 7 - CopySource(xpixel+PIXEL,ypixel+(yoffset >> 9),7,2, - SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR,LOBYTE(VALUE)<<1); -#undef PIXEL -#undef COLOR -#undef VALUE - bDirty = true; - } - yoffset += 0x400; - } - - return bDirty; -} - /* Color Reference Tests: @@ -1699,300 +736,8 @@ Color Reference Tests: */ //=========================================================================== -BYTE MixColors(BYTE c1, BYTE c2) -{ - // For tv emulation HGR Video Mode - #define COMBINATION(c1,c2,ref1,ref2) (((c1)==(ref1)&&(c2)==(ref2)) || ((c1)==(ref2)&&(c2)==(ref1))) - - if (c1 == c2) - return c1; - if (COMBINATION(c1,c2,HGR_BLUE,HGR_ORANGE)) - return HGR_GREY1; - else if (COMBINATION(c1,c2,HGR_GREEN,HGR_VIOLET)) - return HGR_GREY2; - else if (COMBINATION(c1,c2,HGR_ORANGE,HGR_GREEN)) - return HGR_YELLOW; - else if (COMBINATION(c1,c2,HGR_BLUE,HGR_GREEN)) - return HGR_AQUA; - else if (COMBINATION(c1,c2,HGR_BLUE,HGR_VIOLET)) - return HGR_PURPLE; - else if (COMBINATION(c1,c2,HGR_ORANGE,HGR_VIOLET)) - return HGR_PINK; - else - return MONOCHROME_CUSTOM; // visible failure indicator - -#undef COMBINATION -} - - -//=========================================================================== -void CreateColorMixMap() -{ - // For tv emulation HGR Video Mode - #define FROM_NEIGHBOUR 0x00 - - int t,m,b; - BYTE cTop, cMid, cBot; - WORD mixTop, mixBot; - -#define MIX_THRESHOLD 0x12 // bottom 2 HGR colors - - for (t=0; t<6; t++) - for (m=0; m<6; m++) - for (b=0; b<6; b++) { - cTop = t | 0x10; - cMid = m | 0x10; - cBot = b | 0x10; - if (cMid < MIX_THRESHOLD) { - mixTop = mixBot = cMid; - } else { - if (cTop < MIX_THRESHOLD) { - mixTop = FROM_NEIGHBOUR; - } else { - mixTop = MixColors(cMid,cTop); - } - if (cBot < MIX_THRESHOLD) { - mixBot = FROM_NEIGHBOUR; - } else { - mixBot = MixColors(cMid,cBot); - } - if (mixTop == FROM_NEIGHBOUR && mixBot != FROM_NEIGHBOUR) { - mixTop = mixBot; - } else if (mixBot == FROM_NEIGHBOUR && mixTop != FROM_NEIGHBOUR) { - mixBot = mixTop; - } else if (mixBot == FROM_NEIGHBOUR && mixTop == FROM_NEIGHBOUR) { - mixBot = mixTop = cMid; - } - } - colormixmap[t][m][b] = (mixTop << 8) | mixBot; - } -#undef FROM_NEIGHBOUR -} - -//=========================================================================== -void __stdcall MixColorsVertical(int matx, int maty) -{ - // For tv emulation HGR Video Mode - - WORD twoHalfPixel; - int bot1idx, bot2idx; - - if (SW_MIXED && maty > 159) { - if (maty < 161) { - bot1idx = hgrpixelmatrix[matx][maty+1] & 0x0F; - bot2idx = 0; - } else { - bot1idx = bot2idx = 0; - } - } else { - bot1idx = hgrpixelmatrix[matx][maty+1] & 0x0F; - bot2idx = hgrpixelmatrix[matx][maty+2] & 0x0F; - } - - twoHalfPixel = colormixmap[hgrpixelmatrix[matx][maty-2] & 0x0F] - [hgrpixelmatrix[matx][maty-1] & 0x0F] - [hgrpixelmatrix[matx][maty ] & 0x0F]; - colormixbuffer[0] = (twoHalfPixel & 0xFF00) >> 8; - colormixbuffer[1] = twoHalfPixel & 0x00FF; - - twoHalfPixel = colormixmap[hgrpixelmatrix[matx][maty-1] & 0x0F] - [hgrpixelmatrix[matx][maty ] & 0x0F] - [bot1idx]; - colormixbuffer[2] = (twoHalfPixel & 0xFF00) >> 8; - colormixbuffer[3] = twoHalfPixel & 0x00FF; - - twoHalfPixel = colormixmap[hgrpixelmatrix[matx][maty ] & 0x0F] - [bot1idx] - [bot2idx]; - colormixbuffer[4] = (twoHalfPixel & 0xFF00) >> 8; - colormixbuffer[5] = twoHalfPixel & 0x00FF; -} - -//=========================================================================== - -static inline void __stdcall CopyMixedSource8(int x, int y, int sourcex, int sourcey) -{ - // For tv emulation HGR Video Mode - - const BYTE* const currsourceptr = g_aSourceStartofLine[sourcey]+sourcex; - BYTE* const currdestptr = g_aFrameBufferOffset[y*2] + (x*2); - - const int matx = x; - const int maty = HGR_MATRIX_YOFFSET + y; - const int hgrlinesabove = (y > 0) ? 1 : 0; - const int hgrlinesbelow = SW_MIXED ? ((y < 159)? 1:0) : ((y < 191)? 1:0); - const int istart = 2 - (hgrlinesabove*2); - const int iend = 3 + (hgrlinesbelow*2); - - // transfer 7 pixels (i.e. the visible part of an apple hgr-byte) from row to pixelmatrix - for (int count = 0, bufxoffset = 0; count < 7; count++, bufxoffset += 2) - { - hgrpixelmatrix[matx+count][maty] = *(currsourceptr+bufxoffset); - - // color mixing between adjacent scanlines at current x position - MixColorsVertical(matx+count, maty); - - // transfer up to 6 mixed (half-)pixels of current column to framebuffer - BYTE* currptr = currdestptr+bufxoffset; - if (hgrlinesabove) - currptr += g_nFrameBufferPitch * 2; - - for (int i = istart; i <= iend; currptr -= g_nFrameBufferPitch, i++) - { - if (g_uHalfScanLines && (i & 1)) - *currptr = *(currptr+1) = 0; // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows) - else - *currptr = *(currptr+1) = colormixbuffer[i]; - } - } -} - -// For tv emulation HGR Video Mode -static void __stdcall CopyMixedSource(int x, int y, int sourcex, int sourcey) -{ - if (!g_bIsFullScreen || !GetFullScreen32Bit()) - { - CopyMixedSource8(x,y,sourcex,sourcey); - return; - } - - const BYTE* const currsourceptr = g_aSourceStartofLine[sourcey]+sourcex; - UINT32* const currdestptr = (UINT32*) (g_aFrameBufferOffset[ y*2 ] + (x*2)*sizeof(UINT32)); - - const int matx = x; - const int maty = HGR_MATRIX_YOFFSET + y; - const int hgrlinesabove = (y > 0) ? 1 : 0; - const int hgrlinesbelow = SW_MIXED ? ((y < 159)? 1:0) : ((y < 191)? 1:0); - const int istart = 2 - (hgrlinesabove*2); - const int iend = 3 + (hgrlinesbelow*2); - - // transfer 7 pixels (i.e. the visible part of an apple hgr-byte) from row to pixelmatrix - for (int count = 0, bufxoffset = 0; count < 7; count++, bufxoffset += 2) - { - hgrpixelmatrix[matx+count][maty] = *(currsourceptr+bufxoffset); - - // color mixing between adjacent scanlines at current x position - MixColorsVertical(matx+count, maty); - - // transfer up to 6 mixed (half-)pixels of current column to framebuffer - UINT32* currptr = currdestptr+bufxoffset; - if (hgrlinesabove) - currptr += (g_nFrameBufferPitch / sizeof(UINT32)) * 2; - - for (int i = istart; i <= iend; currptr -= g_nFrameBufferPitch/sizeof(UINT32), i++) - { - if (g_uHalfScanLines && (i & 1)) - { - // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows) - *currptr = *(currptr+1) = 0; - } - else - { - const RGBQUAD& rRGB = g_pFramebufferinfo->bmiColors[ colormixbuffer[i] ]; - const UINT32 rgb = (((UINT32)rRGB.rgbRed)<<16) | (((UINT32)rRGB.rgbGreen)<<8) | ((UINT32)rRGB.rgbBlue); - *currptr = *(currptr+1) = rgb; - } - } - } -} - -//=========================================================================== -bool UpdateHiResCell (int x, int y, int xpixel, int ypixel, int offset) -{ - bool bDirty = false; - int yoffset = 0; - while (yoffset < 0x2000) - { -#if 0 // TRACE_VIDEO - static char sText[ 256 ]; - sprintf(sText, "x: %3d y: %3d xpix: %3d ypix: %3d offset: %04X \n" - , x, y, xpixel, ypixel, offset, yoffset - ); - OutputDebugString("sText"); -#endif - - BYTE byteval1 = (x > 0) ? *(g_pHiresBank0+offset+yoffset-1) : 0; - BYTE byteval2 = *(g_pHiresBank0+offset+yoffset ); - BYTE byteval3 = (x < 39) ? *(g_pHiresBank0+offset+yoffset+1) : 0; - if ((byteval2 != *(vidlastmem+offset+yoffset+0x2000)) || - ((x > 0) && ((byteval1 & 0x60) != (*(vidlastmem+offset+yoffset+0x1FFF) & 0x60))) || - ((x < 39) && ((byteval3 & 0x03) != (*(vidlastmem+offset+yoffset+0x2001) & 0x03))) || - g_VideoForceFullRedraw) - { -#define COLOFFS (((byteval1 & 0x60) << 2) | \ - ((byteval3 & 0x03) << 5)) - if (g_eVideoType == VT_COLOR_TVEMU) - { - CopyMixedSource( - xpixel >> 1, (ypixel+(yoffset >> 9)) >> 1, - SRCOFFS_HIRES+COLOFFS+((x & 1) << 4), (((int)byteval2) << 1) - ); - } - else - { - CopySource( - xpixel,ypixel+(yoffset >> 9), - 14,2, // 2x upscale: 280x192 -> 560x384 - SRCOFFS_HIRES+COLOFFS+((x & 1) << 4), (((int)byteval2) << 1) - ); - } -#undef COLOFFS - bDirty = true; - } - yoffset += 0x400; - } - - return bDirty; -} - -//=========================================================================== -bool UpdateLoResCell (int x, int y, int xpixel, int ypixel, int offset) -{ - BYTE val = *(g_pTextBank0+offset); - if ((val != *(vidlastmem+offset+0x400)) || g_VideoForceFullRedraw) - { - CopySource(xpixel,ypixel, - 14,8, - SRCOFFS_LORES+((x & 1) << 1),((val & 0xF) << 4)); - CopySource(xpixel,ypixel+8, - 14,8, - SRCOFFS_LORES+((x & 1) << 1),(val & 0xF0)); - return true; - } - - return false; -} - -//=========================================================================== - #define ROL_NIB(x) ( (((x)<<1)&0xF) | (((x)>>3)&1) ) -bool UpdateDLoResCell (int x, int y, int xpixel, int ypixel, int offset) -{ - BYTE auxval = *(g_pTextBank1 + offset); - BYTE mainval = *(g_pTextBank0 + offset); - - if ( (auxval != *(vidlastmem+offset)) || - (mainval != *(vidlastmem+offset+0x400)) || - g_VideoForceFullRedraw - ) - { - const BYTE auxval_h = auxval >> 4; - const BYTE auxval_l = auxval & 0xF; - auxval = (ROL_NIB(auxval_h)<<4) | ROL_NIB(auxval_l); // Fix Bug #14879 - - CopySource( xpixel,ypixel , 7,8,SRCOFFS_LORES+((x & 1) << 1),((auxval & 0xF) << 4)); - CopySource( xpixel,ypixel+8, 7,8,SRCOFFS_LORES+((x & 1) << 1),(auxval & 0xF0)); - // - CopySource( xpixel+7,ypixel , 7,8, SRCOFFS_LORES+((x & 1) << 1),((mainval & 0xF) << 4)); - CopySource( xpixel+7,ypixel+8, 7,8, SRCOFFS_LORES+((x & 1) << 1),(mainval & 0xF0)); - return true; - } - - return false; -} - - // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- // diff --git a/source/Video.h b/source/Video.h index c5293287..467cca14 100644 --- a/source/Video.h +++ b/source/Video.h @@ -67,8 +67,6 @@ typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int); // Prototypes _______________________________________________________ -void CreateColorMixMap(); - BOOL VideoApparentlyDirty (); void VideoBenchmark (); void VideoChooseMonochromeColor (); // FIXME: Should be moved to PageConfig and call VideoSetMonochromeColor() From 581bb332fe34e4b3beeaa453c5eaadc274ddedea Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 31 Dec 2014 19:38:36 -0800 Subject: [PATCH 006/121] Debugger 2.8.0.9b: BLOAD now recognizes the extensions .hgr or .hgr2 to load to $2000, or $4000 respectfully --- source/Debugger/Debug.cpp | 69 ++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 4a183ceb..54c445f5 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4215,9 +4215,50 @@ Update_t CmdMemoryLoad (int nArgs) { bBankSpecified = false; } -// TODO: check if extension ".hgr", ".hgr2", ".dhgr", ".dhgr2" - if (g_aArgs[ iArgComma1 ].eToken != TOKEN_COMMA) - return Help_Arg_1( CMD_MEMORY_LOAD ); + + struct KnownFileType_t + { + char *pExtension; + int nAddress; + int nLength; + }; + + const KnownFileType_t aFileTypes[] = + { + { "" , 0, 0 } // n/a + ,{ ".hgr" , 0x2000, 0x2000 } + ,{ ".hgr2", 0x4000, 0x2000 } + // TODO: extension ".dhgr", ".dhgr2" + }; + const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t ); + const KnownFileType_t *pFileType = NULL; + + char *pFileName = g_aArgs[ 1 ].sArg; + int nLen = strlen( pFileName ); + char *pEnd = pFileName + + nLen - 1; + while( pEnd > pFileName ) + { + if( *pEnd == '.' ) + { + for( int i = 1; i < nFileTypes; i++ ) + { + if( strcmp( pEnd, aFileTypes[i].pExtension ) == 0 ) + { + pFileType = &aFileTypes[i]; + break; + } + } + } + + if( pFileType ) + break; + + pEnd--; + } + + if( !pFileType ) + if (g_aArgs[ iArgComma1 ].eToken != TOKEN_COMMA) + return Help_Arg_1( CMD_MEMORY_LOAD ); TCHAR sLoadSaveFilePath[ MAX_PATH ]; _tcscpy( sLoadSaveFilePath, g_sCurrentDir ); // TODO: g_sDebugDir @@ -4227,9 +4268,19 @@ Update_t CmdMemoryLoad (int nArgs) WORD nAddressEnd = 0; int nAddressLen = 0; - RangeType_t eRange; - eRange = Range_Get( nAddressStart, nAddress2, iArgAddress ); - if (nArgs > iArgComma2) + if( pFileType ) + { + nAddressStart = pFileType->nAddress; + nAddressLen = pFileType->nLength; + nAddressEnd = pFileType->nLength + nAddressLen; + } + + RangeType_t eRange = RANGE_MISSING_ARG_2; + + if (g_aArgs[ iArgComma1 ].eToken == TOKEN_COMMA) + eRange = Range_Get( nAddressStart, nAddress2, iArgAddress ); + + if( nArgs > iArgComma2 ) { if (eRange == RANGE_MISSING_ARG_2) { @@ -4245,7 +4296,7 @@ Update_t CmdMemoryLoad (int nArgs) if (bHaveFileName) { - _tcscpy( g_sMemoryLoadSaveFileName, g_aArgs[ 1 ].sArg ); + _tcscpy( g_sMemoryLoadSaveFileName, pFileName ); } _tcscat( sLoadSaveFilePath, g_sMemoryLoadSaveFileName ); @@ -4275,7 +4326,9 @@ Update_t CmdMemoryLoad (int nArgs) size_t nRead = fread( pMemBankBase+nAddressStart, nAddressLen, 1, hFile ); if (nRead == 1) { - ConsoleBufferPush( TEXT( "Loaded." ) ); + char text[ 128 ]; + sprintf( text, "Loaded @ A$%04X,L$%04X", nAddressStart, nAddressLen ); + ConsoleBufferPush( text ); } else { From 28cd63fc841f328705f8836fc8aba82e61e4a538 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 09:59:09 -0800 Subject: [PATCH 007/121] Fix: 50% Half Scan Lines wasn't being applied on intial setup --- source/Applewin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 03ea0cbd..c8e9e37f 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -409,8 +409,6 @@ void LoadConfiguration(void) case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. } - NTSC_VideoInitAppleType(); - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &joytype[JN_JOYSTICK0])) LoadConfigOldJoystick(JN_JOYSTICK0); if (!REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &joytype[JN_JOYSTICK1])) @@ -432,6 +430,7 @@ void LoadConfiguration(void) REGLOAD(TEXT(REGVALUE_ENHANCE_DISK_SPEED),(DWORD *)&enhancedisk); Config_Load_Video(); + VideoReinitialize(); REGLOAD(TEXT("Uthernet Active") ,(DWORD *)&tfe_enabled); From 1087f738d501c81f691a151270138ac953db5020 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 09:59:58 -0800 Subject: [PATCH 008/121] Fix monochrome RGB colors --- source/NTSC.cpp | 65 ++++++++++++++++++++++++++++++++++----- source/Video.cpp | 79 +++++++++--------------------------------------- source/Video.h | 2 +- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 2805ec97..ae0d7d91 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -119,6 +119,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned char g_aNTSCMonoTelevision [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; static unsigned char g_aNTSCColorTelevision[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; +// g_aNTSCMonoMonitor * g_nMonochromeRGB -> g_aNTSCMonoMonitorCustom +// g_aNTSCMonoTelevision * g_nMonochromeRGB -> g_aNTSCMonoTelevisionCustom + static unsigned char g_aNTSCMonoMonitorCustom [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + static unsigned char g_aNTSCMonoTelevisionCustom [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + #define NUM_SIGZEROS 2 #define NUM_SIGPOLES 2 #define SIGGAIN 7.614490548f @@ -280,6 +285,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA void init_chroma_phase_table(); void updateColorPhase(); void updateVideoHorzEOL(); + void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ); //=========================================================================== inline float clampZeroOne( const float & x ) @@ -522,6 +528,7 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit make_csbits(); init_video_tables(); init_chroma_phase_table(); + updateMonochromeColor( 0xFF, 0xFF, 0xFF ); for (int y = 0; y < 384; y++) g_NTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; @@ -625,12 +632,12 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit static void ntscMonoSinglePixel (int compositeSignal) { - SINGLEPIXEL(compositeSignal, g_aNTSCMonoMonitor); + SINGLEPIXEL(compositeSignal, g_aNTSCMonoMonitorCustom); } static void ntscMonoDoublePixel (int compositeSignal) { - DOUBLEPIXEL(compositeSignal, g_aNTSCMonoMonitor); + DOUBLEPIXEL(compositeSignal, g_aNTSCMonoMonitorCustom); } static void ntscColorSinglePixel (int compositeSignal) @@ -648,12 +655,12 @@ static void ntscColorDoublePixel (int compositeSignal) static void ntscMonoTVSinglePixel (int compositeSignal) { - SINGLETVPIXEL(compositeSignal, g_aNTSCMonoTelevision); + SINGLETVPIXEL(compositeSignal, g_aNTSCMonoTelevisionCustom); } static void ntscMonoTVDoublePixel (int compositeSignal) { - DOUBLETVPIXEL(compositeSignal, g_aNTSCMonoTelevision); + DOUBLETVPIXEL(compositeSignal, g_aNTSCMonoTelevisionCustom); } static void ntscColorTVSinglePixel (int compositeSignal) @@ -671,11 +678,30 @@ static void ntscColorTVDoublePixel (int compositeSignal) static void (*ntscMonoPixel)(int) = ntscMonoSinglePixel; static void (*ntscColorPixel)(int) = ntscColorSinglePixel; +//=========================================================================== +void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) +{ + for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ ) + { + g_aNTSCMonoMonitorCustom[ iSample ][ _B ] = (g_aNTSCMonoMonitor[ iSample ][_B] * b) >> 8; + g_aNTSCMonoMonitorCustom[ iSample ][ _G ] = (g_aNTSCMonoMonitor[ iSample ][_G] * g) >> 8; + g_aNTSCMonoMonitorCustom[ iSample ][ _R ] = (g_aNTSCMonoMonitor[ iSample ][_R] * r) >> 8; + g_aNTSCMonoMonitorCustom[ iSample ][ _A ] = 0xFF; + + g_aNTSCMonoTelevisionCustom[ iSample ][ _B ] = (g_aNTSCMonoTelevision[ iSample ][_B] * b) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ][ _G ] = (g_aNTSCMonoTelevision[ iSample ][_G] * g) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ][ _B ] = (g_aNTSCMonoTelevision[ iSample ][_R] * r) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ][ _A ] = 0xFF; + } +} + + //=========================================================================== void NTSC_SetVideoStyle() // (int v, int s) { int v = g_eVideoType; int s = g_uHalfScanLines; + uint8_t r, g, b; switch (v) { @@ -712,10 +738,35 @@ void NTSC_SetVideoStyle() // (int v, int s) break; // case VT_MONO_WHITE: //VT_MONO_MONITOR: //3: - case VT_MONO_AMBER: // RGB(0xFF,0x80,0x00) - case VT_MONO_GREEN: // RGB(0x00,0xC0,0x00) - case VT_MONO_WHITE: // RGB(0xFF,0xFF,0xFF) + case VT_MONO_AMBER: + r = 0xFF; + g = 0x80; + b = 0x00; + goto _mono; + + case VT_MONO_GREEN: + r = 0x00; + g = 0xC0; + b = 0x00; + goto _mono; + + case VT_MONO_WHITE: + r = 0xFF; + g = 0xFF; + b = 0xFF; + goto _mono; + case VT_MONO_HALFPIXEL_REAL: + // From WinGDI.h + // #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) + //#define GetRValue(rgb) (LOBYTE(rgb)) + //#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) + //#define GetBValue(rgb) (LOBYTE((rgb)>>16)) + r = (g_nMonochromeRGB >> 0) & 0xFF; + g = (g_nMonochromeRGB >> 8) & 0xFF; + b = (g_nMonochromeRGB >> 16) & 0xFF; +_mono: + updateMonochromeColor( r, g, b ); // Custom Monochrome color if (s) { ntscMonoPixel = ntscColorPixel = ntscMonoSinglePixel; } diff --git a/source/Video.cpp b/source/Video.cpp index 043e8634..6a7a941f 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -262,9 +262,9 @@ static bool g_bVideoUpdatedThisFrame = false; static LPBYTE framebufferaddr = (LPBYTE)0; static LONG g_nFrameBufferPitch = 0; -COLORREF monochrome = RGB(0xC0,0xC0,0xC0); -static BOOL rebuiltsource = 0; -static LPBYTE vidlastmem = NULL; +COLORREF g_nMonochromeRGB = RGB(0xC0,0xC0,0xC0); +static BOOL rebuiltsource = 0; +static LPBYTE vidlastmem = NULL; static UINT g_uVideoMode = VF_TEXT; @@ -324,7 +324,6 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) void V_CreateIdentityPalette (); void V_CreateDIBSections (); - HBRUSH V_CreateCustomBrush (COLORREF nColor); /** Our BitBlit() / VRAM_Copy() @param dx Dst X @@ -379,6 +378,7 @@ void VideoInitialize () g_pFramebufferinfo->bmiHeader.biClrUsed = 0; NTSC_VideoCreateDIBSection(); +// VideoReinitialize(); // Can't call here since Config_Video_Load() hasn't been called yet } //=========================================================================== @@ -439,15 +439,15 @@ void V_CreateIdentityPalette () SETFRAMECOLOR(HGR_PINK, 0xFF,0x32,0xB5); // 0xD0,0x40,0xA0 -> 0xFF,0x32,0xB5 SETFRAMECOLOR( MONOCHROME_CUSTOM - , GetRValue(monochrome) - , GetGValue(monochrome) - , GetBValue(monochrome) + , GetRValue(g_nMonochromeRGB) + , GetGValue(g_nMonochromeRGB) + , GetBValue(g_nMonochromeRGB) ); SETFRAMECOLOR( MONOCHROME_CUSTOM_50 - , ((GetRValue(monochrome)/2) & 0xFF) - , ((GetGValue(monochrome)/2) & 0xFF) - , ((GetBValue(monochrome)/2) & 0xFF) + , ((GetRValue(g_nMonochromeRGB)/2) & 0xFF) + , ((GetGValue(g_nMonochromeRGB)/2) & 0xFF) + , ((GetBValue(g_nMonochromeRGB)/2) & 0xFF) ); SETFRAMECOLOR( MONOCHROME_AMBER , 0xFF,0x80,0x01); // Used for Monochrome Hi-Res graphics not text! @@ -620,57 +620,6 @@ struct BRUSHBMP BYTE bBits[64]; }; -HBRUSH V_CreateCustomBrush(COLORREF nColor) -{ - BRUSHBMP brbmp; - BYTE *pBytes; - int i; - //DWORD dwBits[6][2] = - //{ - // {0x000000ff,0x00000000}, // HS_HORIZONTAL 0 /* ----- */ - // {0x10101010,0x10101010}, // HS_VERTICAL 1 /* ||||| */ - // {0x01020408,0x10204080}, // HS_FDIAGONAL 2 /* \\\\\ */ - // {0x80402010,0x08040201}, // HS_BDIAGONAL 3 /* ///// */ - // {0x101010ff,0x10101010}, // HS_CROSS 4 /* +++++ */ - // {0x81422418,0x18244281}, // HS_DIAGCROSS 5 /* xxxxx */ - //}; - // if ((HatchStyle < 0) || (HatchStyle > 6)) - // return 0; - - int HatchStyle = 0; - DWORD dwBits[1][2] = - { -// {0xff00ff00,0xff00ff00} // every other scan line - {0xFFFFFFFF,0xFFFFFFFF} - }; - - memset (&brbmp, 0, sizeof (brbmp)); - - brbmp.bmi.biSize = sizeof (BITMAPINFOHEADER); - brbmp.bmi.biWidth = 8; - brbmp.bmi.biHeight = 8; - brbmp.bmi.biPlanes = 1; - brbmp.bmi.biBitCount = 1; - brbmp.bmi.biClrUsed = 2; - brbmp.bmi.biClrImportant = 2; - - // Initialize the palette of the bitmap. - brbmp.dwPal[0] = PALETTERGB(0x00,0x00,0x00); - brbmp.dwPal[1] = PALETTERGB( - (BYTE)((nColor >> 16) & 0xff), - (BYTE)((nColor >> 8) & 0xff), - (BYTE)((nColor >> 0) & 0xff)); - - // Write the hatch data to the bitmap. - pBytes = (BYTE *)&dwBits[HatchStyle]; - for (i = 0; i < 8; i++) - brbmp.bBits[i*4] = *pBytes++; - - // Return the handle of the brush created. - return CreateDIBPatternBrushPt (&brbmp, DIB_RGB_COLORS); -} - - //=========================================================================== static void CreateLookup_TextCommon(HDC hDstDC, DWORD rop) @@ -1043,12 +992,12 @@ void VideoChooseMonochromeColor () ZeroMemory(&cc,sizeof(CHOOSECOLOR)); cc.lStructSize = sizeof(CHOOSECOLOR); cc.hwndOwner = g_hFrameWindow; - cc.rgbResult = monochrome; + cc.rgbResult = g_nMonochromeRGB; cc.lpCustColors = customcolors + 1; cc.Flags = CC_RGBINIT | CC_SOLIDCOLOR; if (ChooseColor(&cc)) { - monochrome = cc.rgbResult; + g_nMonochromeRGB = cc.rgbResult; VideoReinitialize(); if ((g_nAppMode != MODE_LOGO) && (g_nAppMode != MODE_DEBUG)) { @@ -1933,7 +1882,7 @@ void Config_Load_Video() { REGLOAD(TEXT(REGVALUE_VIDEO_MODE ),&g_eVideoType); REGLOAD(TEXT(REGVALUE_VIDEO_HALF_SCAN_LINES),&g_uHalfScanLines); - REGLOAD(TEXT(REGVALUE_VIDEO_MONO_COLOR ),&monochrome); + REGLOAD(TEXT(REGVALUE_VIDEO_MONO_COLOR ),&g_nMonochromeRGB); if (g_eVideoType >= NUM_VIDEO_MODES) g_eVideoType = VT_COLOR_STANDARD; // Old default: VT_COLOR_TVEMU @@ -1943,7 +1892,7 @@ void Config_Save_Video() { REGSAVE(TEXT(REGVALUE_VIDEO_MODE ),g_eVideoType); REGSAVE(TEXT(REGVALUE_VIDEO_HALF_SCAN_LINES),g_uHalfScanLines); - REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),monochrome); + REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),g_nMonochromeRGB); } // ____________________________________________________________________ diff --git a/source/Video.h b/source/Video.h index 467cca14..ca75cc14 100644 --- a/source/Video.h +++ b/source/Video.h @@ -57,7 +57,7 @@ extern HBITMAP g_hLogoBitmap; -extern COLORREF monochrome; // saved +extern COLORREF g_nMonochromeRGB; // saved extern DWORD g_eVideoType; // saved extern DWORD g_uHalfScanLines; // saved extern uint8_t *g_pFramebufferbits; From 75c5cc815133f4cd4a15770b6daf6b6774788cf0 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 11:48:59 -0800 Subject: [PATCH 009/121] Fix broken MIXED mode, fix Debugger view output, change main loop to call VideoRefresh() --- source/Applewin.cpp | 4 +++- source/Debugger/Debug.cpp | 9 ++++++--- source/Debugger/Debug.h | 2 +- source/Frame.cpp | 5 +++-- source/Video.cpp | 22 ++++++++++++++++------ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index c8e9e37f..e22cfec3 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -230,7 +230,9 @@ void ContinueExecution(void) if (g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; - VideoEndOfVideoFrame(); // NTSC currently requires this ... need to investigate why + + // VideoEndOfVideoFrame(); // NTSC_TODO: is this still required? updates flash: if ((SW_TEXT || SW_MIXED) ) g_bTextFlashFlag = true + VideoRefreshScreen(0); // Just copy the output of our Apple framebuffer to the system Back Buffer MB_EndOfVideoFrame(); } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 54c445f5..e200553f 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -310,7 +310,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA bool g_bTraceHeader = false; // semaphore, flag header to be printed DWORD extbench = 0; - bool g_bDebuggerViewingAppleOutput = false; + int g_bDebuggerViewingAppleOutput = false; // NOTE: alias for bVideoModeFlags! bool g_bIgnoreNextKey = false; @@ -6096,9 +6096,12 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags ) default: break; } - +#if _DEBUG + if(!bVideoModeFlags) + MessageBoxA( NULL, "bVideoModeFlags = ZERO !?", "Information", MB_OK ); +#endif + g_bDebuggerViewingAppleOutput = bVideoModeFlags; VideoRefreshScreen( bVideoModeFlags ); - g_bDebuggerViewingAppleOutput = true; return UPDATE_NOTHING; // intentional } diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h index 26c3ecec..8c1fdc79 100644 --- a/source/Debugger/Debug.h +++ b/source/Debugger/Debug.h @@ -105,7 +105,7 @@ extern int g_aDisasmTargets[ MAX_DISPLAY_LINES ]; // Display - extern bool g_bDebuggerViewingAppleOutput; + extern int g_bDebuggerViewingAppleOutput; // Font extern int g_nFontHeight; diff --git a/source/Frame.cpp b/source/Frame.cpp index ad696605..aa87f0f6 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -565,6 +565,7 @@ static void DrawFrameWindow () else // Win7: In fullscreen mode with 1 redraw, the the screen doesn't get redraw. //VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) + //VideoRefreshScreen(0); VideoRedrawScreen(); // DD Full-Screen Palette: BUGFIX: needs to come _after_ all drawing... @@ -1173,8 +1174,8 @@ LRESULT CALLBACK FrameWndProc ( VideoReinitialize(); if ((g_nAppMode != MODE_LOGO) || ((g_nAppMode == MODE_DEBUG) && (g_bDebuggerViewingAppleOutput))) { - VideoRedrawScreen(); - g_bDebuggerViewingAppleOutput = true; + //VideoRedrawScreen(); + VideoRefreshScreen( g_bDebuggerViewingAppleOutput ); } Config_Save_Video(); diff --git a/source/Video.cpp b/source/Video.cpp index 6a7a941f..41f87868 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1196,7 +1196,8 @@ void VideoRealizePalette(HDC dc) void VideoRedrawScreen () { g_VideoForceFullRedraw = 1; - VideoRefreshScreen( g_uVideoMode ); + + VideoRefreshScreen( g_uVideoMode ); //g_uVideoMode ); } //=========================================================================== @@ -1246,8 +1247,11 @@ void VideoRefreshScreen ( int bVideoModeFlags ) DebugRefresh(0); #endif - NTSC_SetVideoMode( bVideoModeFlags ); - g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + if( bVideoModeFlags ) + { + NTSC_SetVideoMode( bVideoModeFlags ); + g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + } // NTSC_BEGIN: wsVideoRefresh() LPBYTE pDstFrameBufferBits = 0; @@ -1256,8 +1260,14 @@ void VideoRefreshScreen ( int bVideoModeFlags ) if (hFrameDC) { -// StretchBlt(hFrameDC,0,0,VIEWPORTCX,VIEWPORTCY,g_hDeviceDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,SRCCOPY); - StretchBlt(hFrameDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,g_hDeviceDC,0,0,FRAMEBUFFER_W,FRAMEBUFFER_H,SRCCOPY); + StretchBlt( + hFrameDC, + 0,0, + FRAMEBUFFER_W,FRAMEBUFFER_H, + g_hDeviceDC, + 0,0, + FRAMEBUFFER_W,FRAMEBUFFER_H, + SRCCOPY ); GdiFlush(); } @@ -1335,7 +1345,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) // NB. Deferring the update by just setting /g_VideoForceFullRedraw/ is not an option, since this doesn't provide "flip-immediate" // // Ultimately this isn't the correct solution, and proper cycle-accurate video rendering should be done, but this is a much bigger job! - // + // TODO: Is MemReadFloatingBus() still accurate now that we have proper per cycle video rendering?? if (!g_bVideoUpdatedThisFrame) { From d75cc2b3307228e568d4f4c4c65d150e3cd2febe Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 11:59:54 -0800 Subject: [PATCH 010/121] Cleanup and factor common code, macro VIDEO_DRAW_BITS() to inline function --- source/NTSC.cpp | 251 +++++++++++++++++++++++++++--------------------- 1 file changed, 143 insertions(+), 108 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index ae0d7d91..bde4c349 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -87,7 +87,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA unsigned char * g_NTSC_Lines[384]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 static unsigned g_nTextFlashCounter = 0; - static unsigned g_nTextFlashMask = 0; + static uint16_t g_nTextFlashMask = 0; static unsigned g_aPixelMaskGR[16]; static uint16_t g_aPixelDoubleMaskHGR[128]; // hgrbits -> g_aPixelDoubleMaskHGR: 7-bit mono 280 pixels to 560 pixel doubling @@ -675,7 +675,7 @@ static void ntscColorTVDoublePixel (int compositeSignal) updateColorPhase(); } -static void (*ntscMonoPixel)(int) = ntscMonoSinglePixel; +static void (*ntscMonoPixel )(int) = ntscMonoSinglePixel ; static void (*ntscColorPixel)(int) = ntscColorSinglePixel; //=========================================================================== @@ -789,56 +789,58 @@ unsigned char NTSC_VideoByte (unsigned long cycle) return mem[0]; } -#define VIDEO_DRAW_BITS() do { \ - if (g_nColorBurstPixels < 2) \ - { \ - /* #1 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - /* #2 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - /* #3 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - /* #4 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - /* #5 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - /* #6 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - /* #7 of 7 */ \ - ntscMonoPixel(bt & 1); bt >>= 1; \ - ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1;\ - } \ - else \ - { \ - /* #1 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); bt >>= 1; \ - /* #2 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); bt >>= 1; \ - /* #3 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); bt >>= 1; \ - /* #4 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); bt >>= 1; \ - /* #5 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); bt >>= 1; \ - /* #6 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); bt >>= 1; \ - /* #7 of 7 */ \ - ntscColorPixel(bt & 1); bt >>= 1; \ - ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1;\ - } \ -} while(0) +inline +void VIDEO_DRAW_BITS( uint16_t bt ) +{ + if (g_nColorBurstPixels < 2) + { + /* #1 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #2 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #3 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #4 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #5 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #6 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #7 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + } + else + { + /* #1 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #2 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #3 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #4 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #5 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #6 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #7 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + } +} inline void updateVideoHorzEOL() @@ -871,7 +873,7 @@ void updateVideoHorzEOL() if (++g_nTextFlashCounter == 16) { g_nTextFlashCounter = 0; - g_nTextFlashMask ^= 0xffff; + g_nTextFlashMask ^= -1; // 16-bits } } @@ -889,6 +891,9 @@ void updateVideoHorzEOL() //=========================================================================== void NTSC_VideoUpdateCycles( long cycles ) { +// if( !g_bFullSpeed ) +// g_pNTSC_FuncVideoUpdate( uElapsedCycles ); +// else for( ; cycles > 0; cycles-- ) { if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) @@ -900,7 +905,7 @@ void NTSC_VideoUpdateCycles( long cycles ) if (++g_nTextFlashCounter == 16) { g_nTextFlashCounter = 0; - g_nTextFlashMask ^= 0xffff; + g_nTextFlashMask ^= -1; // 16-bits } // Force full refresh @@ -918,11 +923,16 @@ void NTSC_VideoUpdateCycles( long cycles ) } } +inline +uint8_t getCharSetBits(int iBank) +{ + return csbits[g_nVideoCharSet][iBank][g_nVideoClockVert & 7]; +} //=========================================================================== void NTSC_UpdateVideoText40 (long ticks) { - unsigned ad, bt; + unsigned ad; for (; ticks; --ticks) { @@ -937,12 +947,13 @@ void NTSC_UpdateVideoText40 (long ticks) { if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * main = MemGetMainPtr(ad); - - bt = g_aPixelDoubleMaskHGR[(csbits[g_nVideoCharSet][main[0]][g_nVideoClockVert & 7]) & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - if (0 == g_nVideoCharSet && 0x40 == (main[0] & 0xC0)) - bt ^= g_nTextFlashMask; - VIDEO_DRAW_BITS(); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint8_t c = getCharSetBits(m); + uint16_t bits = g_aPixelDoubleMaskHGR[c & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) + bits ^= g_nTextFlashMask; + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -952,7 +963,7 @@ void NTSC_UpdateVideoText40 (long ticks) //=========================================================================== void NTSC_UpdateVideoText80 (long ticks) { - unsigned int ad, bt, mbt, abt; + unsigned int ad; for (; ticks; --ticks) { @@ -967,27 +978,39 @@ void NTSC_UpdateVideoText80 (long ticks) { if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * aux = MemGetAuxPtr(ad); - unsigned char * main = MemGetMainPtr(ad); - - mbt = csbits[g_nVideoCharSet][main[0]][g_nVideoClockVert & 7]; - if (0 == g_nVideoCharSet && 0x40 == (main[0] & 0xC0)) mbt ^= g_nTextFlashMask; + uint8_t *pAux = MemGetAuxPtr(ad); + uint8_t *pMain = MemGetMainPtr(ad); - abt = csbits[g_nVideoCharSet][aux[0]][g_nVideoClockVert & 7]; - if (0 == g_nVideoCharSet && 0x40 == (aux[0] & 0xC0)) abt ^= g_nTextFlashMask; + uint8_t m = pMain[0]; + uint8_t a = pAux [0]; - bt = (mbt << 7) | abt; - VIDEO_DRAW_BITS(); + uint16_t main = getCharSetBits( m ); + uint16_t aux = getCharSetBits( a ); + + if ((0 == g_nVideoCharSet) && 0x40 == (m & 0xC0)) + main ^= g_nTextFlashMask; + + if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) + aux ^= g_nTextFlashMask; + + uint16_t bits = (main << 7) | aux; + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); } } +inline +uint8_t getLoResBits( int iBank ) +{ + return g_aPixelMaskGR[ (iBank >> (g_nVideoClockVert & 4)) & 0xF ]; +} + //=========================================================================== void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores { - unsigned ad, bt; + unsigned ad; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { @@ -1007,9 +1030,11 @@ void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * main = MemGetMainPtr(ad); - bt = g_aPixelDoubleMaskHGR[(0xFF & g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits - VIDEO_DRAW_BITS(); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint8_t lo = getLoResBits( m ); + uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -1019,7 +1044,7 @@ void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores //=========================================================================== void NTSC_UpdateVideoLores40 (long ticks) { - unsigned ad, bt; + unsigned ad; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { @@ -1039,9 +1064,11 @@ void NTSC_UpdateVideoLores40 (long ticks) } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * main = MemGetMainPtr(ad); - bt = g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> ((1 - (g_nVideoClockHorz & 1)) * 2); - VIDEO_DRAW_BITS(); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint8_t lo = getLoResBits( m ); + uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2); + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -1051,7 +1078,7 @@ void NTSC_UpdateVideoLores40 (long ticks) //=========================================================================== void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores { - unsigned ad, bt, abt, mbt; + unsigned ad; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { @@ -1071,15 +1098,19 @@ void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * aux = MemGetAuxPtr(ad); - unsigned char * main = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pAux = MemGetAuxPtr(ad); - abt = g_aPixelMaskGR[(aux [0] >> (g_nVideoClockVert & 4)) & 0xF] >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); - mbt = g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); - bt = (mbt << 7) | (abt & 0x7f); - - VIDEO_DRAW_BITS(); - g_nLastColumnPixelNTSC = bt & 1; + uint8_t m = pMain[0]; + uint8_t a = pAux [0]; + + uint8_t lo = getLoResBits( m ); + uint8_t hi = getLoResBits( a ); + + uint16_t main = lo >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); + uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); + uint16_t bits = (main << 7) | (aux & 0x7f); + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -1089,7 +1120,8 @@ void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores //=========================================================================== void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires { - unsigned ad, bt; + unsigned ad; + uint16_t bits; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { @@ -1109,13 +1141,15 @@ void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * aux = MemGetAuxPtr(ad); - unsigned char * main = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pAux = MemGetAuxPtr(ad); - bt = ((main[0] & 0x7f) << 7) | (aux[0] & 0x7f); - bt = (bt << 1) | g_nLastColumnPixelNTSC; - VIDEO_DRAW_BITS(); - g_nLastColumnPixelNTSC = bt & 1; + uint8_t m = pMain[0]; + uint8_t a = pAux [0]; + + bits = ((m & 0x7f) << 7) | (a & 0x7f); + bits = (bits << 1) | g_nLastColumnPixelNTSC; + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -1126,7 +1160,7 @@ void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires //=========================================================================== void NTSC_UpdateVideoHires40 (long ticks) { - unsigned ad, bt; + unsigned ad; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { @@ -1146,12 +1180,12 @@ void NTSC_UpdateVideoHires40 (long ticks) } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * main = MemGetMainPtr(ad); - - bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - if (main[0] & 0x80) - bt = (bt << 1) | g_nLastColumnPixelNTSC; - VIDEO_DRAW_BITS(); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + if (m & 0x80) + bits = (bits << 1) | g_nLastColumnPixelNTSC; + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -1161,7 +1195,7 @@ void NTSC_UpdateVideoHires40 (long ticks) //=========================================================================== void NTSC_UpdateVideoDblHires40 (long ticks) // wsUpdateVideoHires0 { - unsigned ad, bt; + unsigned ad; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { @@ -1181,9 +1215,10 @@ void NTSC_UpdateVideoDblHires40 (long ticks) // wsUpdateVideoHires0 } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { - unsigned char * main = MemGetMainPtr(ad); - bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - VIDEO_DRAW_BITS(); + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + VIDEO_DRAW_BITS( bits ); } } updateVideoHorzEOL(); @@ -1202,8 +1237,8 @@ void NTSC_SetVideoTextMode( int cols ) //=========================================================================== void NTSC_SetVideoMode( int bVideoModeFlags ) { - g_nVideoMixed = bVideoModeFlags & VF_MIXED; - g_nVideoCharSet = g_nAltCharSetOffset; + g_nVideoMixed = bVideoModeFlags & VF_MIXED; + g_nVideoCharSet = g_nAltCharSetOffset; g_nTextPage = 1; g_nHiresPage = 1; From e07d80898f10b060591b58fc21a64cc8329c5e36 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 17:19:49 -0800 Subject: [PATCH 011/121] Fix Ctrl-F6 2x zoom --- source/Frame.cpp | 4 ++-- source/Frame.h | 3 +++ source/Video.cpp | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index aa87f0f6..5b521d09 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -62,8 +62,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define MAGICY 5 // 3D border between Apple window & Title bar static const int kDEFAULT_VIEWPORT_SCALE = 2; -static int g_nViewportCX = FRAMEBUFFER_W * kDEFAULT_VIEWPORT_SCALE; -static int g_nViewportCY = FRAMEBUFFER_H * kDEFAULT_VIEWPORT_SCALE; + int g_nViewportCX = FRAMEBUFFER_W * kDEFAULT_VIEWPORT_SCALE; + int g_nViewportCY = FRAMEBUFFER_H * kDEFAULT_VIEWPORT_SCALE; static int g_nViewportScale = kDEFAULT_VIEWPORT_SCALE; // saved REGSAVE static int g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE; diff --git a/source/Frame.h b/source/Frame.h index 47af25a1..357177c7 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -30,9 +30,12 @@ // Win32 extern HWND g_hFrameWindow; extern BOOL g_bIsFullScreen; + extern int g_nViewportCX; + extern int g_nViewportCY; extern BOOL g_bConfirmReboot; // saved PageConfig REGSAVE extern BOOL g_bMultiMon; + // Emulator extern bool g_bFreshReset; extern std::string PathFilename[2]; diff --git a/source/Video.cpp b/source/Video.cpp index 41f87868..ec0e3240 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1263,10 +1263,10 @@ void VideoRefreshScreen ( int bVideoModeFlags ) StretchBlt( hFrameDC, 0,0, - FRAMEBUFFER_W,FRAMEBUFFER_H, + g_nViewportCX,g_nViewportCY, //dst g_hDeviceDC, 0,0, - FRAMEBUFFER_W,FRAMEBUFFER_H, + FRAMEBUFFER_W,FRAMEBUFFER_H, // src SRCCOPY ); GdiFlush(); } From 29fbe9515ccb7935c24c06c4bcd427c79a44e7c2 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 17:20:36 -0800 Subject: [PATCH 012/121] Fix all GR modes -- need 16-bits for pixel color --- source/NTSC.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index bde4c349..52b76759 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -988,10 +988,10 @@ void NTSC_UpdateVideoText80 (long ticks) uint16_t aux = getCharSetBits( a ); if ((0 == g_nVideoCharSet) && 0x40 == (m & 0xC0)) - main ^= g_nTextFlashMask; + main ^= g_nTextFlashMask; if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) - aux ^= g_nTextFlashMask; + aux ^= g_nTextFlashMask; uint16_t bits = (main << 7) | aux; VIDEO_DRAW_BITS( bits ); @@ -1002,9 +1002,9 @@ void NTSC_UpdateVideoText80 (long ticks) } inline -uint8_t getLoResBits( int iBank ) +uint16_t getLoResBits( uint8_t iByte ) { - return g_aPixelMaskGR[ (iBank >> (g_nVideoClockVert & 4)) & 0xF ]; + return g_aPixelMaskGR[ (iByte >> (g_nVideoClockVert & 4)) & 0xF ]; } //=========================================================================== @@ -1032,7 +1032,7 @@ void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores { uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; - uint8_t lo = getLoResBits( m ); + uint16_t lo = getLoResBits( m ); uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits VIDEO_DRAW_BITS( bits ); } @@ -1066,7 +1066,7 @@ void NTSC_UpdateVideoLores40 (long ticks) { uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; - uint8_t lo = getLoResBits( m ); + uint16_t lo = getLoResBits( m ); uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2); VIDEO_DRAW_BITS( bits ); } @@ -1104,8 +1104,8 @@ void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores uint8_t m = pMain[0]; uint8_t a = pAux [0]; - uint8_t lo = getLoResBits( m ); - uint8_t hi = getLoResBits( a ); + uint16_t lo = getLoResBits( m ); + uint16_t hi = getLoResBits( a ); uint16_t main = lo >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); From c68c50c8dbd7868b5297ee874e58c17d823ac3d5 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 17:32:09 -0800 Subject: [PATCH 013/121] Fix mode Color Text Optimized -> Monochrome TV --- source/NTSC.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 52b76759..2e0e1058 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -690,7 +690,7 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) g_aNTSCMonoTelevisionCustom[ iSample ][ _B ] = (g_aNTSCMonoTelevision[ iSample ][_B] * b) >> 8; g_aNTSCMonoTelevisionCustom[ iSample ][ _G ] = (g_aNTSCMonoTelevision[ iSample ][_G] * g) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ][ _B ] = (g_aNTSCMonoTelevision[ iSample ][_R] * r) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ][ _R ] = (g_aNTSCMonoTelevision[ iSample ][_R] * r) >> 8; g_aNTSCMonoTelevisionCustom[ iSample ][ _A ] = 0xFF; } } @@ -729,6 +729,10 @@ void NTSC_SetVideoStyle() // (int v, int s) break; case VT_COLOR_TEXT_OPTIMIZED: // VT_MONO_TV: //2: + r = 0xFF; + g = 0xFF; + b = 0xFF; + updateMonochromeColor( r, g, b ); // Custom Monochrome color if (s) { ntscMonoPixel = ntscColorPixel = ntscMonoTVSinglePixel; } From 88b1b493e4d0c758e311fc4db77e1e622b9aaa6a Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 22:03:34 -0800 Subject: [PATCH 014/121] Set 40/80 Char Set if not Apple ][ --- source/Video.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index ec0e3240..058ce02e 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1311,8 +1311,8 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) { case 0x00: g_uVideoMode &= ~VF_80STORE; ; break; case 0x01: g_uVideoMode |= VF_80STORE; ; break; - case 0x0C: if (!IS_APPLE2) g_uVideoMode &= ~VF_80COL; NTSC_SetVideoTextMode(40); break; - case 0x0D: if (!IS_APPLE2) g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80); break; + case 0x0C: if (!IS_APPLE2){g_uVideoMode &= ~VF_80COL; NTSC_SetVideoTextMode(40);}; break; + case 0x0D: if (!IS_APPLE2){g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80);}; break; case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off case 0x0F: if (!IS_APPLE2) g_nAltCharSetOffset = 256; break; // Alternate char set on case 0x50: g_uVideoMode &= ~VF_TEXT; break; From 6c9032d67e24013411d2f10aafd50ffe1e583b43 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 22:04:38 -0800 Subject: [PATCH 015/121] Cleanup: Alphabetize functions --- source/NTSC.cpp | 757 +++++++++++++++++++++++++----------------------- 1 file changed, 393 insertions(+), 364 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 2e0e1058..d70be425 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -53,7 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees #else // sharpness is higher, less color bleed #if CHROMA_FILTER == 2 - #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = signal_prefilter(z); + #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = init_signal_prefilter(z); #else // #define CYCLESTART DEG_TO_RAD(90) // (PI*0.5) // PI/2 = 90 degrees // HGR: Great, GR: fail on brown #define CYCLESTART DEG_TO_RAD(115.f) // GR perfect match of slow method @@ -276,6 +276,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void (* g_pNTSC_FuncVideoText )(long) = NTSC_UpdateVideoText40; void (* g_pNTSC_FuncVideoUpdate)(long) = NTSC_UpdateVideoText40; + static void (*ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; + static void (*ntscColorPixel)(int) = 0; //ntscColorSinglePixel; + // Prototypes // prototype from CPU.h //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles); @@ -285,7 +288,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA void init_chroma_phase_table(); void updateColorPhase(); void updateVideoHorzEOL(); - void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ); + + static void ntscMonoSinglePixel (int compositeSignal); + static void ntscMonoDoublePixel (int compositeSignal); + static void ntscColorSinglePixel (int compositeSignal); + static void ntscColorDoublePixel (int compositeSignal); + static void ntscMonoTVSinglePixel (int compositeSignal); + static void ntscMonoTVDoublePixel (int compositeSignal); + static void ntscColorTVSinglePixel (int compositeSignal); + static void ntscColorTVDoublePixel (int compositeSignal); + static void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ); //=========================================================================== inline float clampZeroOne( const float & x ) @@ -295,6 +307,18 @@ inline float clampZeroOne( const float & x ) /* ...... */ return x; } +//=========================================================================== +inline uint8_t getCharSetBits(int iChar) +{ + return csbits[g_nVideoCharSet][iChar][g_nVideoClockVert & 7]; +} + +//=========================================================================== +inline uint16_t getLoResBits( uint8_t iByte ) +{ + return g_aPixelMaskGR[ (iByte >> (g_nVideoClockVert & 4)) & 0xF ]; +} + //=========================================================================== inline void updateColorPhase() { @@ -303,17 +327,156 @@ inline void updateColorPhase() } //=========================================================================== -void NTSC_VideoInitAppleType () +inline void updateVideoHorzEOL() { - int model = g_Apple2Type; + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + g_nVideoClockHorz = 0; + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + //VIDEO_DRAW_ENDLINE(); + if (g_nColorBurstPixels < 2) + { + ntscMonoPixel(g_nLastColumnPixelNTSC); + ntscMonoPixel(0); + ntscMonoPixel(0); + ntscMonoPixel(0); + } + else + { + ntscColorPixel(g_nLastColumnPixelNTSC); + ntscColorPixel(0); + ntscColorPixel(0); + ntscColorPixel(0); + } + } - // anything other than low bit set means not II/II+ - if (model & 0xFFFE) - g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; - else - g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + if (++g_nTextFlashCounter == 16) + { + g_nTextFlashCounter = 0; + g_nTextFlashMask ^= -1; // 16-bits + } + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; + g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; + g_nLastColumnPixelNTSC = 0; + g_nSignalBitsNTSC = 0; + } + } } +#define SINGLE_SCANLINE_MONITOR(signal,table) \ + do { \ + unsigned int *cp, *mp; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ + *((unsigned int *)vbp0) = *cp; \ + mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ + *mp = ((*cp & 0x00fcfcfc) >> 2) + 0xff000000; \ + vbp0 += 4; \ + } while(0) + +#define SINGLE_SCANLINE_TELEVISION(signal,table) \ + do { \ + unsigned int ntscp, prevp, betwp; \ + unsigned int *prevlin, *between; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ + between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ + ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ + prevp = *prevlin; \ + betwp = ntscp - ((ntscp & 0x00fcfcfc) >> 2); \ + *between = betwp | 0xff000000; \ + *((unsigned int *)vbp0) = ntscp; \ + vbp0 += 4; \ + } while(0) + +#define DOUBLE_SCANLINE_MONITOR(signal,table) \ + do { \ + unsigned int *cp, *mp; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ + mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ + *((unsigned int *)vbp0) = *mp = *cp; \ + vbp0 += 4; \ + } while(0) + +#define DOUBLE_SCANLINE_TELEVISION(signal,table) \ + do { \ + unsigned int ntscp, prevp, betwp; \ + unsigned int *prevlin, *between; \ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ + prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ + between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ + ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ + prevp = *prevlin; \ + betwp = ((ntscp & 0x00fefefe) >> 1) + ((prevp & 0x00fefefe) >> 1); \ + *between = betwp | 0xff000000; \ + *((unsigned int *)vbp0) = ntscp; \ + vbp0 += 4; \ + } while(0) + +//=========================================================================== +inline +void VIDEO_DRAW_BITS( uint16_t bt ) +{ + if (g_nColorBurstPixels < 2) + { + /* #1 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #2 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #3 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #4 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #5 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #6 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); bt >>= 1; + /* #7 of 7 */ + ntscMonoPixel(bt & 1); bt >>= 1; + ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + } + else + { + /* #1 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #2 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #3 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #4 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #5 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #6 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; + /* #7 of 7 */ + ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + } +} + +//=========================================================================== static void init_video_tables (void) { /* @@ -337,7 +500,8 @@ static void init_video_tables (void) // sadly float64 precision is needed #define real double -static real signal_prefilter (real z) +//=========================================================================== +static real init_signal_prefilter (real z) { static real xv[NUM_SIGZEROS + 1] = { 0,0,0 }; static real yv[NUM_SIGPOLES + 1] = { 0,0,0 }; @@ -352,10 +516,11 @@ static real signal_prefilter (real z) return yv[2]; } -static real luma0_filter (real z) +//=========================================================================== +static real init_luma0_filter (real z) { - static real xv[NUM_LUMZEROS + 1]; - static real yv[NUM_LUMPOLES + 1]; + static real xv[NUM_LUMZEROS + 1] = { 0,0,0 }; + static real yv[NUM_LUMPOLES + 1] = { 0,0,0 }; xv[0] = xv[1]; xv[1] = xv[2]; @@ -367,10 +532,11 @@ static real luma0_filter (real z) return yv[2]; } -static real luma1_filter (real z) +//=========================================================================== +static real init_luma1_filter (real z) { - static real xv[NUM_LUMZEROS + 1]; - static real yv[NUM_LUMPOLES + 1]; + static real xv[NUM_LUMZEROS + 1] = { 0,0,0}; + static real yv[NUM_LUMPOLES + 1] = { 0,0,0}; xv[0] = xv[1]; xv[1] = xv[2]; @@ -382,10 +548,11 @@ static real luma1_filter (real z) return yv[2]; } -static real chroma_filter (real z) +//=========================================================================== +static real init_chroma_filter (real z) { - static real xv[NUM_CHRZEROS + 1]; - static real yv[NUM_CHRPOLES + 1]; + static real xv[NUM_CHRZEROS + 1] = {0,0,0}; + static real yv[NUM_CHRPOLES + 1] = {0,0,0}; xv[0] = xv[1]; xv[1] = xv[2]; @@ -426,10 +593,10 @@ static void init_chroma_phase_table (void) { #if CHROMA_BLUR //z = z * 1.25; - zz = signal_prefilter(z); - c = chroma_filter(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees - y0 = luma0_filter(zz); - y1 = luma1_filter(zz - c); + zz = init_signal_prefilter(z); + c = init_chroma_filter(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + y0 = init_luma0_filter(zz); + y1 = init_luma1_filter(zz - c); #else // CHROMA_BLUR y0 = y0 + (z - y0) / 4.0; y1 = y0; // fix TV mode @@ -449,7 +616,7 @@ static void init_chroma_phase_table (void) #endif #if CHROMA_FILTER == 2 // more blur, muted chroma fringe // White has too much ringing, and the color fringes are muted - c = signal_prefilter(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + c = init_signal_prefilter(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees #endif #endif // CHROMA_BLUR c = c * 2.f; @@ -523,160 +690,56 @@ static void init_chroma_phase_table (void) } //=========================================================================== -void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit -{ - make_csbits(); - init_video_tables(); - init_chroma_phase_table(); - updateMonochromeColor( 0xFF, 0xFF, 0xFF ); - - for (int y = 0; y < 384; y++) - g_NTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; - - vbp0 = g_NTSC_Lines[0]; // wsLines - -#if HGR_TEST_PATTERN -// Michael -- Init HGR to almost all-possible-combinations -// CALL-151 -// C050 C053 C057 - unsigned char b = 0; - unsigned char *main, *aux; - - for( unsigned page = 0; page < 2; page++ ) - { - for( unsigned w = 0; w < 2; w++ ) // 16 cols - { - for( unsigned z = 0; z < 2; z++ ) // 8 cols - { - b = 0; // 4 columns * 64 rows - for( unsigned x = 0; x < 4; x++ ) // 4 cols - { - for( unsigned y = 0; y < 64; y++ ) // 1 col - { - unsigned y2 = y*2; - ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; - ad += 0x2000*page; - main = MemGetMainPtr(ad); - aux = MemGetAuxPtr (ad); - main[0] = b; main[1] = w + page*0x80; - aux [0] = z; aux [1] = 0; - - y2 = y*2 + 1; - ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; - ad += 0x2000*page; - main = MemGetMainPtr(ad); - aux = MemGetAuxPtr (ad); - main[0] = 0; main[1] = w + page*0x80; - aux [0] = b; aux [1] = 0; - - b++; - } - } - } - } - } -#endif - -} - -#define SINGLEPIXEL(signal,table) \ - do { \ - unsigned int *cp, *mp; \ - g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ - *((unsigned int *)vbp0) = *cp; \ - mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ - *mp = ((*cp & 0x00fcfcfc) >> 2) + 0xff000000; \ - vbp0 += 4; \ - } while(0) - -#define SINGLETVPIXEL(signal,table) \ - do { \ - unsigned int ntscp, prevp, betwp; \ - unsigned int *prevlin, *between; \ - g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ - between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ - ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ - prevp = *prevlin; \ - betwp = ntscp - ((ntscp & 0x00fcfcfc) >> 2); \ - *between = betwp | 0xff000000; \ - *((unsigned int *)vbp0) = ntscp; \ - vbp0 += 4; \ - } while(0) - -#define DOUBLEPIXEL(signal,table) \ - do { \ - unsigned int *cp, *mp; \ - g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ - mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ - *((unsigned int *)vbp0) = *mp = *cp; \ - vbp0 += 4; \ - } while(0) - -#define DOUBLETVPIXEL(signal,table) \ - do { \ - unsigned int ntscp, prevp, betwp; \ - unsigned int *prevlin, *between; \ - g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ - between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ - ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ - prevp = *prevlin; \ - betwp = ((ntscp & 0x00fefefe) >> 1) + ((prevp & 0x00fefefe) >> 1); \ - *between = betwp | 0xff000000; \ - *((unsigned int *)vbp0) = ntscp; \ - vbp0 += 4; \ - } while(0) - -static void ntscMonoSinglePixel (int compositeSignal) -{ - SINGLEPIXEL(compositeSignal, g_aNTSCMonoMonitorCustom); -} - -static void ntscMonoDoublePixel (int compositeSignal) -{ - DOUBLEPIXEL(compositeSignal, g_aNTSCMonoMonitorCustom); -} - -static void ntscColorSinglePixel (int compositeSignal) -{ - SINGLEPIXEL(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); - updateColorPhase(); -} - -static void ntscColorDoublePixel (int compositeSignal) -{ - DOUBLEPIXEL(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); - updateColorPhase(); -} - - -static void ntscMonoTVSinglePixel (int compositeSignal) -{ - SINGLETVPIXEL(compositeSignal, g_aNTSCMonoTelevisionCustom); -} - -static void ntscMonoTVDoublePixel (int compositeSignal) -{ - DOUBLETVPIXEL(compositeSignal, g_aNTSCMonoTelevisionCustom); -} - static void ntscColorTVSinglePixel (int compositeSignal) { - SINGLETVPIXEL(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + SINGLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); updateColorPhase(); } +//=========================================================================== static void ntscColorTVDoublePixel (int compositeSignal) { - DOUBLETVPIXEL(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + DOUBLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); updateColorPhase(); } -static void (*ntscMonoPixel )(int) = ntscMonoSinglePixel ; -static void (*ntscColorPixel)(int) = ntscColorSinglePixel; +//=========================================================================== +static void ntscColorSinglePixel (int compositeSignal) +{ + SINGLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateColorPhase(); +} + +//=========================================================================== +static void ntscColorDoublePixel (int compositeSignal) +{ + DOUBLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateColorPhase(); +} + +//=========================================================================== +static void ntscMonoSinglePixel (int compositeSignal) +{ + SINGLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCMonoMonitorCustom); +} + +//=========================================================================== +static void ntscMonoDoublePixel (int compositeSignal) +{ + DOUBLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCMonoMonitorCustom); +} + +//=========================================================================== +static void ntscMonoTVSinglePixel (int compositeSignal) +{ + SINGLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCMonoTelevisionCustom); +} + +//=========================================================================== +static void ntscMonoTVDoublePixel (int compositeSignal) +{ + DOUBLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCMonoTelevisionCustom); +} //=========================================================================== void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) @@ -695,6 +758,55 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) } } +//=========================================================================== +void NTSC_SetVideoTextMode( int cols ) +{ + if( cols == 40 ) + g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; + else + g_pNTSC_FuncVideoText = NTSC_UpdateVideoText80; +} + +//=========================================================================== +void NTSC_SetVideoMode( int bVideoModeFlags ) +{ + g_nVideoMixed = bVideoModeFlags & VF_MIXED; + g_nVideoCharSet = g_nAltCharSetOffset; + + g_nTextPage = 1; + g_nHiresPage = 1; + if (bVideoModeFlags & VF_PAGE2) { + if (0 == (bVideoModeFlags & VF_80STORE)) { + g_nTextPage = 2; + g_nHiresPage = 2; + } + } + + if (bVideoModeFlags & VF_TEXT) { + if (bVideoModeFlags & VF_80COL) + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText80; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40; + } + else if (bVideoModeFlags & VF_HIRES) { + if (bVideoModeFlags & VF_DHIRES) + if (bVideoModeFlags & VF_80COL) + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires80; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires40; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoHires40; + } + else { + if (bVideoModeFlags & VF_DHIRES) + if (bVideoModeFlags & VF_80COL) + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores80; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores40; + else + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoLores40; + } +} //=========================================================================== void NTSC_SetVideoStyle() // (int v, int s) @@ -781,158 +893,6 @@ _mono: } } -int NTSC_VideoIsVbl () -{ - return (g_nVideoClockVert >= VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockVert < VIDEO_SCANNER_MAX_VERT); -} - -unsigned char NTSC_VideoByte (unsigned long cycle) -{ - unsigned char * mem; - mem = MemGetMainPtr(g_aHorzClockMemAddress[ g_nVideoClockHorz ]); - return mem[0]; -} - -inline -void VIDEO_DRAW_BITS( uint16_t bt ) -{ - if (g_nColorBurstPixels < 2) - { - /* #1 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; - /* #2 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; - /* #3 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; - /* #4 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; - /* #5 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; - /* #6 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; - /* #7 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; - } - else - { - /* #1 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; - /* #2 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; - /* #3 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; - /* #4 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; - /* #5 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; - /* #6 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; - /* #7 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; - } -} - -inline -void updateVideoHorzEOL() -{ - if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) - { - g_nVideoClockHorz = 0; - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - //VIDEO_DRAW_ENDLINE(); - if (g_nColorBurstPixels < 2) - { - ntscMonoPixel(g_nLastColumnPixelNTSC); - ntscMonoPixel(0); - ntscMonoPixel(0); - ntscMonoPixel(0); - } - else - { - ntscColorPixel(g_nLastColumnPixelNTSC); - ntscColorPixel(0); - ntscColorPixel(0); - ntscColorPixel(0); - } - } - - if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) - { - g_nVideoClockVert = 0; - if (++g_nTextFlashCounter == 16) - { - g_nTextFlashCounter = 0; - g_nTextFlashMask ^= -1; // 16-bits - } - } - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; - g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; - g_nLastColumnPixelNTSC = 0; - g_nSignalBitsNTSC = 0; - } - } -} - -// Light-weight Video Clock Update -//=========================================================================== -void NTSC_VideoUpdateCycles( long cycles ) -{ -// if( !g_bFullSpeed ) -// g_pNTSC_FuncVideoUpdate( uElapsedCycles ); -// else - for( ; cycles > 0; cycles-- ) - { - if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) - { - g_nVideoClockHorz = 0; - if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) - { - g_nVideoClockVert = 0; - if (++g_nTextFlashCounter == 16) - { - g_nTextFlashCounter = 0; - g_nTextFlashMask ^= -1; // 16-bits - } - - // Force full refresh - g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); - } - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; - g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; - g_nLastColumnPixelNTSC = 0; - g_nSignalBitsNTSC = 0; - } - } - } -} - -inline -uint8_t getCharSetBits(int iBank) -{ - return csbits[g_nVideoCharSet][iBank][g_nVideoClockVert & 7]; -} - //=========================================================================== void NTSC_UpdateVideoText40 (long ticks) { @@ -982,6 +942,10 @@ void NTSC_UpdateVideoText80 (long ticks) { if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { +vbp0[0] ^= 0xD5; +vbp0[1] ^= 0xAA; +vbp0[2] ^= 0xFF; + uint8_t *pAux = MemGetAuxPtr(ad); uint8_t *pMain = MemGetMainPtr(ad); @@ -1005,12 +969,6 @@ void NTSC_UpdateVideoText80 (long ticks) } } -inline -uint16_t getLoResBits( uint8_t iByte ) -{ - return g_aPixelMaskGR[ (iByte >> (g_nVideoClockVert & 4)) & 0xF ]; -} - //=========================================================================== void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores { @@ -1160,7 +1118,6 @@ void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires } } - //=========================================================================== void NTSC_UpdateVideoHires40 (long ticks) { @@ -1230,51 +1187,123 @@ void NTSC_UpdateVideoDblHires40 (long ticks) // wsUpdateVideoHires0 } //=========================================================================== -void NTSC_SetVideoTextMode( int cols ) +unsigned char NTSC_VideoByte (unsigned long cycle) { - if( cols == 40 ) - g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; - else - g_pNTSC_FuncVideoText = NTSC_UpdateVideoText80; + unsigned char * mem; + mem = MemGetMainPtr(g_aHorzClockMemAddress[ g_nVideoClockHorz ]); + return mem[0]; } //=========================================================================== -void NTSC_SetVideoMode( int bVideoModeFlags ) +void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit { - g_nVideoMixed = bVideoModeFlags & VF_MIXED; - g_nVideoCharSet = g_nAltCharSetOffset; + make_csbits(); + init_video_tables(); + init_chroma_phase_table(); + updateMonochromeColor( 0xFF, 0xFF, 0xFF ); - g_nTextPage = 1; - g_nHiresPage = 1; - if (bVideoModeFlags & VF_PAGE2) { - if (0 == (bVideoModeFlags & VF_80STORE)) { - g_nTextPage = 2; - g_nHiresPage = 2; + for (int y = 0; y < 384; y++) + g_NTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; + + vbp0 = g_NTSC_Lines[0]; // wsLines + + ntscMonoPixel = ntscMonoSinglePixel ; + ntscColorPixel = ntscColorSinglePixel; + +#if HGR_TEST_PATTERN +// Michael -- Init HGR to almost all-possible-combinations +// CALL-151 +// C050 C053 C057 + unsigned char b = 0; + unsigned char *main, *aux; + + for( unsigned page = 0; page < 2; page++ ) + { + for( unsigned w = 0; w < 2; w++ ) // 16 cols + { + for( unsigned z = 0; z < 2; z++ ) // 8 cols + { + b = 0; // 4 columns * 64 rows + for( unsigned x = 0; x < 4; x++ ) // 4 cols + { + for( unsigned y = 0; y < 64; y++ ) // 1 col + { + unsigned y2 = y*2; + ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; + ad += 0x2000*page; + main = MemGetMainPtr(ad); + aux = MemGetAuxPtr (ad); + main[0] = b; main[1] = w + page*0x80; + aux [0] = z; aux [1] = 0; + + y2 = y*2 + 1; + ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; + ad += 0x2000*page; + main = MemGetMainPtr(ad); + aux = MemGetAuxPtr (ad); + main[0] = 0; main[1] = w + page*0x80; + aux [0] = b; aux [1] = 0; + + b++; + } + } + } } } +#endif - if (bVideoModeFlags & VF_TEXT) { - if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText80; - else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40; - } - else if (bVideoModeFlags & VF_HIRES) { - if (bVideoModeFlags & VF_DHIRES) - if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires80; - else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires40; - else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoHires40; - } - else { - if (bVideoModeFlags & VF_DHIRES) - if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores80; - else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores40; - else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoLores40; +} + +//=========================================================================== +void NTSC_VideoInitAppleType () +{ + int model = g_Apple2Type; + + // anything other than low bit set means not II/II+ + if (model & 0xFFFE) + g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; + else + g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; +} + +//=========================================================================== +int NTSC_VideoIsVbl () +{ + return (g_nVideoClockVert >= VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockVert < VIDEO_SCANNER_MAX_VERT); +} + +// Light-weight Video Clock Update +//=========================================================================== +void NTSC_VideoUpdateCycles( long cycles ) +{ +// if( !g_bFullSpeed ) +// g_pNTSC_FuncVideoUpdate( uElapsedCycles ); +// else + for( ; cycles > 0; cycles-- ) + { + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + g_nVideoClockHorz = 0; + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + if (++g_nTextFlashCounter == 16) + { + g_nTextFlashCounter = 0; + g_nTextFlashMask ^= -1; // 16-bits + } + + // Force full refresh + g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; + g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; + g_nLastColumnPixelNTSC = 0; + g_nSignalBitsNTSC = 0; + } + } } } From a29444eb6cb0731d23a4aec8e2b05292c8eb4e12 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 22:05:40 -0800 Subject: [PATCH 016/121] Fix 80-col using out-of-bounds Char Set --- source/NTSC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index d70be425..fc887ce2 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -771,7 +771,7 @@ void NTSC_SetVideoTextMode( int cols ) void NTSC_SetVideoMode( int bVideoModeFlags ) { g_nVideoMixed = bVideoModeFlags & VF_MIXED; - g_nVideoCharSet = g_nAltCharSetOffset; + g_nVideoCharSet = g_nAltCharSetOffset != 0; g_nTextPage = 1; g_nHiresPage = 1; From 581e1467bc9774ccf9b5dd3b0f403d7dde815074 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 22:11:17 -0800 Subject: [PATCH 017/121] Remove debug text80 watermark --- source/NTSC.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index fc887ce2..53a49dc2 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -942,10 +942,6 @@ void NTSC_UpdateVideoText80 (long ticks) { if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { -vbp0[0] ^= 0xD5; -vbp0[1] ^= 0xAA; -vbp0[2] ^= 0xFF; - uint8_t *pAux = MemGetAuxPtr(ad); uint8_t *pMain = MemGetMainPtr(ad); From ce633237e0cbd3ead62a2d683ddd08fb010a52b7 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 22:45:40 -0800 Subject: [PATCH 018/121] Fixed Double Lo-Res and Double Hi-Res --- source/NTSC.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 53a49dc2..4344265d 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -452,27 +452,28 @@ void VIDEO_DRAW_BITS( uint16_t bt ) } else { - /* #1 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; + /* #1 of 7 */ // abcd efgh ijkl mnop + ntscColorPixel(bt & 1); bt >>= 1; // 0abc defg hijk lmno + ntscColorPixel(bt & 1); bt >>= 1; // 00ab cdef ghi jklmn /* #2 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; // 000a bcde fghi jklm + ntscColorPixel(bt & 1); bt >>= 1; // 0000 abcd efgh ijkl /* #3 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0abc defg hijk + ntscColorPixel(bt & 1); bt >>= 1; // 0000 00ab cdef ghij /* #4 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; // 0000 000a bcde fghi + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 abcd efgh /* #5 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0abc defg + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 00ab cdef /* #6 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 000a bcde + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 abcd /* #7 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; - ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 0abc + ntscColorPixel(bt & 1); +g_nLastColumnPixelNTSC=bt & 1 ; bt >>= 1; // 0000 0000 0000 00ab } } @@ -1069,6 +1070,7 @@ void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); uint16_t bits = (main << 7) | (aux & 0x7f); VIDEO_DRAW_BITS( bits ); + g_nLastColumnPixelNTSC = (bits >> 14) & 3; } } updateVideoHorzEOL(); @@ -1108,6 +1110,7 @@ void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires bits = ((m & 0x7f) << 7) | (a & 0x7f); bits = (bits << 1) | g_nLastColumnPixelNTSC; VIDEO_DRAW_BITS( bits ); + g_nLastColumnPixelNTSC = (bits >> 14) & 3; } } updateVideoHorzEOL(); From de00db9cf80c82214a311ab17887b0396b3e72d6 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 22:47:55 -0800 Subject: [PATCH 019/121] Debugger: Fixed view output Double Lo-Res and Double Hi-Res --- source/Debugger/Debug.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index e200553f..a8d6e2a7 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -6097,7 +6097,7 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags ) break; } #if _DEBUG - if(!bVideoModeFlags) + if (bVideoModeFlags == 0) MessageBoxA( NULL, "bVideoModeFlags = ZERO !?", "Information", MB_OK ); #endif g_bDebuggerViewingAppleOutput = bVideoModeFlags; @@ -6134,15 +6134,15 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags ) // Lo-Res Update_t CmdViewOutput_GRX (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, 0 ); + return _ViewOutput( VIEW_PAGE_X, VF_80STORE ); // NTSC VideoRefresh() Hack: flags != 0 } Update_t CmdViewOutput_GR1 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, 0 ); + return _ViewOutput( VIEW_PAGE_1, VF_80STORE ); // NTSC VideoRefresh() Hack: flags != 0 } Update_t CmdViewOutput_GR2 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, 0 ); + return _ViewOutput( VIEW_PAGE_2, VF_80STORE ); // NTSC VideoRefresh() Hack: flags != 0 } // Double Lo-Res Update_t CmdViewOutput_DGRX (int nArgs) @@ -6173,15 +6173,15 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags ) // Double Hi-Res Update_t CmdViewOutput_DHGRX (int nArgs) { - return _ViewOutput( VIEW_PAGE_X, VF_HIRES | VF_DHIRES ); + return _ViewOutput( VIEW_PAGE_X, VF_HIRES | VF_DHIRES | VF_80COL ); } Update_t CmdViewOutput_DHGR1 (int nArgs) { - return _ViewOutput( VIEW_PAGE_1, VF_HIRES | VF_DHIRES ); + return _ViewOutput( VIEW_PAGE_1, VF_HIRES | VF_DHIRES | VF_80COL); } Update_t CmdViewOutput_DHGR2 (int nArgs) { - return _ViewOutput( VIEW_PAGE_2, VF_HIRES | VF_DHIRES ); + return _ViewOutput( VIEW_PAGE_2, VF_HIRES | VF_DHIRES | VF_80COL ); } // Watches ________________________________________________________________________________________ From c74cafdadd37c062ba95f9f015a509a082ff7b57 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 23:50:04 -0800 Subject: [PATCH 020/121] Cleanup function prototypes --- source/NTSC.cpp | 549 +++++++++++++++++++++++++----------------------- source/NTSC.h | 9 - 2 files changed, 285 insertions(+), 273 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 4344265d..e827c9b0 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -2,7 +2,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 2010-2011, William S Simms -Copyright (C) 2014 Michael Pohoreski +Copyright (C) 2014-2015 Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -50,7 +50,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #endif #if CHROMA_BLUR - #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees + //#define CYCLESTART (PI/4.f) // PI/4 = 45 degrees + #define CYCLESTART (DEG_TO_RAD(45)) #else // sharpness is higher, less color bleed #if CHROMA_FILTER == 2 #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = init_signal_prefilter(z); @@ -79,12 +80,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define VIDEO_SCANNER_MAX_HORZ 65 // TODO: use Video.cpp: kHClocks #define VIDEO_SCANNER_MAX_VERT 262 // TODO: use Video.cpp: kNTSCScanLines + #define VIDEO_SCANNER_HORZ_COLORBURST_BEG 12 + #define VIDEO_SCANNER_HORZ_COLORBURST_END 16 + #define VIDEO_SCANNER_HORZ_START 25 // first displayable horz scanner index #define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text #define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ]; - unsigned char * g_NTSC_Lines[384]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + unsigned char * g_aNTSC_Lines[384]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 static unsigned g_nTextFlashCounter = 0; static uint16_t g_nTextFlashMask = 0; @@ -273,8 +277,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; - static void (* g_pNTSC_FuncVideoText )(long) = NTSC_UpdateVideoText40; - void (* g_pNTSC_FuncVideoUpdate)(long) = NTSC_UpdateVideoText40; + static void (* g_pNTSC_FuncVideoText )(long) = 0; // NTSC_UpdateVideoText40; + void (* g_pNTSC_FuncVideoUpdate)(long) = 0; // NTSC_UpdateVideoText40; static void (*ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; static void (*ntscColorPixel)(int) = 0; //ntscColorSinglePixel; @@ -289,14 +293,23 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA void updateColorPhase(); void updateVideoHorzEOL(); - static void ntscMonoSinglePixel (int compositeSignal); - static void ntscMonoDoublePixel (int compositeSignal); - static void ntscColorSinglePixel (int compositeSignal); - static void ntscColorDoublePixel (int compositeSignal); + static void NTSC_UpdateVideoDoubleHires40(long cycles6502); + static void NTSC_UpdateVideoDoubleHires80(long cycles6502); + static void NTSC_UpdateVideoDoubleLores40(long cycles6502); + static void NTSC_UpdateVideoDoubleLores80(long cycles6502); + static void NTSC_UpdateVideoSingleHires40(long cycles6502); + static void NTSC_UpdateVideoSingleLores40(long cycles6502); + static void NTSC_UpdateVideoText40 (long cycles6502); + static void NTSC_UpdateVideoText80 (long cycles6502); + + static void ntscMonoSinglePixel (int compositeSignal); + static void ntscMonoDoublePixel (int compositeSignal); + static void ntscColorSinglePixel (int compositeSignal); + static void ntscColorDoublePixel (int compositeSignal); static void ntscMonoTVSinglePixel (int compositeSignal); static void ntscMonoTVDoublePixel (int compositeSignal); - static void ntscColorTVSinglePixel (int compositeSignal); - static void ntscColorTVDoublePixel (int compositeSignal); + static void ntscColorTVSinglePixel(int compositeSignal); + static void ntscColorTVDoublePixel(int compositeSignal); static void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ); //=========================================================================== @@ -310,7 +323,7 @@ inline float clampZeroOne( const float & x ) //=========================================================================== inline uint8_t getCharSetBits(int iChar) { - return csbits[g_nVideoCharSet][iChar][g_nVideoClockVert & 7]; + return csbits[g_nVideoCharSet][iChar][g_nVideoClockVert & 7]; } //=========================================================================== @@ -363,7 +376,7 @@ inline void updateVideoHorzEOL() if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { - vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; + vbp0 = g_aNTSC_Lines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; @@ -424,7 +437,7 @@ inline void updateVideoHorzEOL() //=========================================================================== inline -void VIDEO_DRAW_BITS( uint16_t bt ) +void VIDEO_DRAW_BITS( uint16_t bt ) // VIDEO_DRAW_BITS { if (g_nColorBurstPixels < 2) { @@ -483,11 +496,12 @@ static void init_video_tables (void) /* Convert 7-bit monochrome luminance to 14-bit double pixel luminance Chroma will be applied later based on the color phase in ntscColorDoublePixel( luminanceBit ) - 0x001 -> 0x0003 - 0x002 -> 0x000C - 0x004 -> 0x0030 - 0x008 -> 0x00C0 - 0x100 -> 0x4000 + 0x001 -> 0x0003 + 0x002 -> 0x000C + 0x004 -> 0x0030 + 0x008 -> 0x00C0 + : -> : + 0x100 -> 0x4000 */ for (uint8_t byte = 0; byte < 0x80; byte++ ) // Optimization: hgrbits second 128 entries are mirror of first 128 for (uint8_t bits = 0; bits < 7; bits++ ) // high bit = half pixel shift; pre-optimization: bits < 8 @@ -625,8 +639,8 @@ static void init_chroma_phase_table (void) q = q + (c * sin(phi) - q) / 8.f; phi += RAD_45; //(PI / 4); - if (fabs((RAD_360) - phi) < 0.001) - phi = phi - RAD_360; // 2 * PI; +// if (fabs((RAD_360) - phi) < 0.001) +// phi = phi - RAD_360; // 2 * PI; } // k } // samples @@ -664,7 +678,7 @@ static void init_chroma_phase_table (void) r64 = y0 + (I_TO_R * i) + (Q_TO_R * q); g64 = y0 + (I_TO_G * i) + (Q_TO_G * q); b64 = y0 + (I_TO_B * i) + (Q_TO_B * q); - + b32 = clampZeroOne( (float)b64); g32 = clampZeroOne( (float)g64); r32 = clampZeroOne( (float)r64); @@ -677,7 +691,7 @@ static void init_chroma_phase_table (void) r64 = y1 + (I_TO_R * i) + (Q_TO_R * q); g64 = y1 + (I_TO_G * i) + (Q_TO_G * q); b64 = y1 + (I_TO_B * i) + (Q_TO_B * q); - + b32 = clampZeroOne( (float)b64 ); g32 = clampZeroOne( (float)g64 ); r32 = clampZeroOne( (float)r64 ); @@ -762,7 +776,7 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) //=========================================================================== void NTSC_SetVideoTextMode( int cols ) { - if( cols == 40 ) + if( cols == 40 ) g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; else g_pNTSC_FuncVideoText = NTSC_UpdateVideoText80; @@ -792,34 +806,34 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) else if (bVideoModeFlags & VF_HIRES) { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires80; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleHires80; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires40; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleHires40; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoHires40; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoSingleHires40; } else { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores80; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleLores80; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores40; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleLores40; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoLores40; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoSingleLores40; } } //=========================================================================== void NTSC_SetVideoStyle() // (int v, int s) { - int v = g_eVideoType; - int s = g_uHalfScanLines; + int half = g_uHalfScanLines; uint8_t r, g, b; - switch (v) + switch ( g_eVideoType ) { case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: - if (s) { + if (half) + { ntscMonoPixel = ntscMonoTVSinglePixel; ntscColorPixel = ntscColorTVSinglePixel; } @@ -831,7 +845,8 @@ void NTSC_SetVideoStyle() // (int v, int s) case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1: default: - if (s) { + if (half) + { ntscMonoPixel = ntscMonoSinglePixel; ntscColorPixel = ntscColorSinglePixel; } @@ -846,7 +861,8 @@ void NTSC_SetVideoStyle() // (int v, int s) g = 0xFF; b = 0xFF; updateMonochromeColor( r, g, b ); // Custom Monochrome color - if (s) { + if (half) + { ntscMonoPixel = ntscColorPixel = ntscMonoTVSinglePixel; } else { @@ -884,10 +900,12 @@ void NTSC_SetVideoStyle() // (int v, int s) b = (g_nMonochromeRGB >> 16) & 0xFF; _mono: updateMonochromeColor( r, g, b ); // Custom Monochrome color - if (s) { + if (half) + { ntscMonoPixel = ntscColorPixel = ntscMonoSinglePixel; } - else { + else + { ntscMonoPixel = ntscColorPixel = ntscMonoDoublePixel; } break; @@ -895,15 +913,234 @@ _mono: } //=========================================================================== -void NTSC_UpdateVideoText40 (long ticks) +void NTSC_UpdateVideoDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 { unsigned ad; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText( cycles6502 ); + return; + } + + for (; cycles6502; --cycles6502) + { + UpdateVideoAddressHGR(); - for (; ticks; --ticks) + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + VIDEO_DRAW_BITS( bits ); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires +{ + unsigned ad; + uint16_t bits; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText( cycles6502 ); + return; + } + + for (; cycles6502; --cycles6502) + { + UpdateVideoAddressHGR(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pAux = MemGetAuxPtr(ad); + + uint8_t m = pMain[0]; + uint8_t a = pAux [0]; + + bits = ((m & 0x7f) << 7) | (a & 0x7f); + bits = (bits << 1) | g_nLastColumnPixelNTSC; + VIDEO_DRAW_BITS( bits ); + g_nLastColumnPixelNTSC = (bits >> 14) & 3; + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores +{ + unsigned ad; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText( cycles6502 ); + return; + } + + for (; cycles6502; --cycles6502) { UpdateVideoAddressTXT(); - if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12) + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint16_t lo = getLoResBits( m ); + uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits + VIDEO_DRAW_BITS( bits ); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores +{ + unsigned ad; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText( cycles6502 ); + return; + } + + for (; cycles6502; --cycles6502) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pAux = MemGetAuxPtr(ad); + + uint8_t m = pMain[0]; + uint8_t a = pAux [0]; + + uint16_t lo = getLoResBits( m ); + uint16_t hi = getLoResBits( a ); + + uint16_t main = lo >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); + uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); + uint16_t bits = (main << 7) | (aux & 0x7f); + VIDEO_DRAW_BITS( bits ); + g_nLastColumnPixelNTSC = (bits >> 14) & 3; + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoSingleHires40 (long cycles6502) +{ + unsigned ad; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText( cycles6502 ); + return; + } + + for (; cycles6502; --cycles6502) + { + UpdateVideoAddressHGR(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 + if (m & 0x80) + bits = (bits << 1) | g_nLastColumnPixelNTSC; + VIDEO_DRAW_BITS( bits ); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoSingleLores40 (long cycles6502) +{ + unsigned ad; + + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) + { + g_pNTSC_FuncVideoText( cycles6502 ); + return; + } + + for (; cycles6502; --cycles6502) + { + UpdateVideoAddressTXT(); + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) + { + g_nColorBurstPixels = 1024; + } + else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) + { + uint8_t *pMain = MemGetMainPtr(ad); + uint8_t m = pMain[0]; + uint16_t lo = getLoResBits( m ); + uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2); + VIDEO_DRAW_BITS( bits ); + } + } + updateVideoHorzEOL(); + } +} + +//=========================================================================== +void NTSC_UpdateVideoText40 (long cycles6502) +{ + unsigned ad; + + for (; cycles6502; --cycles6502) + { + UpdateVideoAddressTXT(); + + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) { if (g_nColorBurstPixels > 0) g_nColorBurstPixels -= 1; @@ -934,7 +1171,7 @@ void NTSC_UpdateVideoText80 (long ticks) { UpdateVideoAddressTXT(); - if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12) + if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) { if (g_nColorBurstPixels > 0) g_nColorBurstPixels -= 1; @@ -966,225 +1203,6 @@ void NTSC_UpdateVideoText80 (long ticks) } } -//=========================================================================== -void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores -{ - unsigned ad; - - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) - { - g_pNTSC_FuncVideoText(ticks); - return; - } - - for (; ticks; --ticks) - { - UpdateVideoAddressTXT(); - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12) - { - g_nColorBurstPixels = 1024; - } - else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) - { - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t m = pMain[0]; - uint16_t lo = getLoResBits( m ); - uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits - VIDEO_DRAW_BITS( bits ); - } - } - updateVideoHorzEOL(); - } -} - -//=========================================================================== -void NTSC_UpdateVideoLores40 (long ticks) -{ - unsigned ad; - - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) - { - g_pNTSC_FuncVideoText(ticks); - return; - } - - for (; ticks; --ticks) - { - UpdateVideoAddressTXT(); - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) - { - g_nColorBurstPixels = 1024; - } - else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) - { - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t m = pMain[0]; - uint16_t lo = getLoResBits( m ); - uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2); - VIDEO_DRAW_BITS( bits ); - } - } - updateVideoHorzEOL(); - } -} - -//=========================================================================== -void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores -{ - unsigned ad; - - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) - { - g_pNTSC_FuncVideoText(ticks); - return; - } - - for (; ticks; --ticks) - { - UpdateVideoAddressTXT(); - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) - { - g_nColorBurstPixels = 1024; - } - else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) - { - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t *pAux = MemGetAuxPtr(ad); - - uint8_t m = pMain[0]; - uint8_t a = pAux [0]; - - uint16_t lo = getLoResBits( m ); - uint16_t hi = getLoResBits( a ); - - uint16_t main = lo >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); - uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); - uint16_t bits = (main << 7) | (aux & 0x7f); - VIDEO_DRAW_BITS( bits ); - g_nLastColumnPixelNTSC = (bits >> 14) & 3; - } - } - updateVideoHorzEOL(); - } -} - -//=========================================================================== -void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires -{ - unsigned ad; - uint16_t bits; - - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) - { - g_pNTSC_FuncVideoText(ticks); - return; - } - - for (; ticks; --ticks) - { - UpdateVideoAddressHGR(); - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) - { - g_nColorBurstPixels = 1024; - } - else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) - { - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t *pAux = MemGetAuxPtr(ad); - - uint8_t m = pMain[0]; - uint8_t a = pAux [0]; - - bits = ((m & 0x7f) << 7) | (a & 0x7f); - bits = (bits << 1) | g_nLastColumnPixelNTSC; - VIDEO_DRAW_BITS( bits ); - g_nLastColumnPixelNTSC = (bits >> 14) & 3; - } - } - updateVideoHorzEOL(); - } -} - -//=========================================================================== -void NTSC_UpdateVideoHires40 (long ticks) -{ - unsigned ad; - - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) - { - g_pNTSC_FuncVideoText(ticks); - return; - } - - for (; ticks; --ticks) - { - UpdateVideoAddressHGR(); - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) - { - g_nColorBurstPixels = 1024; - } - else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) - { - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t m = pMain[0]; - uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - if (m & 0x80) - bits = (bits << 1) | g_nLastColumnPixelNTSC; - VIDEO_DRAW_BITS( bits ); - } - } - updateVideoHorzEOL(); - } -} - -//=========================================================================== -void NTSC_UpdateVideoDblHires40 (long ticks) // wsUpdateVideoHires0 -{ - unsigned ad; - - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) - { - g_pNTSC_FuncVideoText(ticks); - return; - } - - for (; ticks; --ticks) - { - UpdateVideoAddressHGR(); - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12)) - { - g_nColorBurstPixels = 1024; - } - else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) - { - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t m = pMain[0]; - uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - VIDEO_DRAW_BITS( bits ); - } - } - updateVideoHorzEOL(); - } -} - //=========================================================================== unsigned char NTSC_VideoByte (unsigned long cycle) { @@ -1202,13 +1220,16 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit updateMonochromeColor( 0xFF, 0xFF, 0xFF ); for (int y = 0; y < 384; y++) - g_NTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; + g_aNTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; - vbp0 = g_NTSC_Lines[0]; // wsLines + vbp0 = g_aNTSC_Lines[0]; // wsLines ntscMonoPixel = ntscMonoSinglePixel ; ntscColorPixel = ntscColorSinglePixel; + g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; + g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40; + #if HGR_TEST_PATTERN // Michael -- Init HGR to almost all-possible-combinations // CALL-151 @@ -1298,7 +1319,7 @@ void NTSC_VideoUpdateCycles( long cycles ) if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { - vbp0 = g_NTSC_Lines[2*g_nVideoClockVert]; + vbp0 = g_aNTSC_Lines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; diff --git a/source/NTSC.h b/source/NTSC.h index d2092891..116cae8e 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -12,15 +12,6 @@ extern void NTSC_SetVideoMode( int flags ); extern void NTSC_SetVideoStyle(); - extern void NTSC_UpdateVideoText40 (long cycles); - extern void NTSC_UpdateVideoText80 (long cyckes); - extern void NTSC_UpdateVideoLores40 (long cycles); - extern void NTSC_UpdateVideoDblLores40(long cycles); - extern void NTSC_UpdateVideoDblLores80(long cycles); - extern void NTSC_UpdateVideoHires40 (long cycles); - extern void NTSC_UpdateVideoDblHires40(long cycles); - extern void NTSC_UpdateVideoDblHires80(long cycles); - extern uint8_t NTSC_VideoByte(unsigned long); extern void NTSC_VideoCreateDIBSection(); extern void NTSC_VideoInit( uint8_t *pFramebuffer ); From 8651da0903c58349d5198d7c12a0f6671f7bc7a8 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 1 Jan 2015 23:54:05 -0800 Subject: [PATCH 021/121] Remove white ringing in Standard Color Monitor --- source/NTSC.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index e827c9b0..48a86cef 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -679,6 +679,14 @@ static void init_chroma_phase_table (void) g64 = y0 + (I_TO_G * i) + (Q_TO_G * q); b64 = y0 + (I_TO_B * i) + (Q_TO_B * q); + // Remove white ringing + if(brightness > 0.9f) + { + b64 += 0.25; + g64 += 0.25; + r64 += 0.25; + } + b32 = clampZeroOne( (float)b64); g32 = clampZeroOne( (float)g64); r32 = clampZeroOne( (float)r64); From 24ac8886c6f3f2f19a969878298f20868c87fe56 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 00:06:49 -0800 Subject: [PATCH 022/121] Cleanup: Global Func Pointer: g_pNTSC_FuncVideoUpdate -> g_pFunc_NTSCVideoUpdateGraphics g_pNTSC_FuncVideoText -> g_pFunc_NTSCVideoUpdateText --- source/CPU/cpu6502.h | 2 +- source/CPU/cpu65C02.h | 2 +- source/CPU/cpu65d02.h | 2 +- source/NTSC.cpp | 148 +++++++++++++++++++++--------------------- source/NTSC.h | 2 +- source/Video.cpp | 2 +- 6 files changed, 79 insertions(+), 79 deletions(-) diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index a22aa764..947334e5 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -325,7 +325,7 @@ static DWORD Cpu6502 (DWORD uTotalCycles) if( g_bFullSpeed ) NTSC_VideoUpdateCycles( uElapsedCycles ); else - g_pNTSC_FuncVideoUpdate( uElapsedCycles ); + g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index 6a9c30f3..545f44ab 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -329,7 +329,7 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) if( g_bFullSpeed ) NTSC_VideoUpdateCycles( uElapsedCycles ); else - g_pNTSC_FuncVideoUpdate( uElapsedCycles ); + g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index 120cbd5b..c082a6c1 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -658,7 +658,7 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) if( g_bFullSpeed ) NTSC_VideoUpdateCycles( uElapsedCycles ); else - g_pNTSC_FuncVideoUpdate( uElapsedCycles ); + g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 48a86cef..96820764 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -277,11 +277,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; - static void (* g_pNTSC_FuncVideoText )(long) = 0; // NTSC_UpdateVideoText40; - void (* g_pNTSC_FuncVideoUpdate)(long) = 0; // NTSC_UpdateVideoText40; + static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; + void (* g_pFunc_NTSCVideoUpdateGraphics)(long) = 0; // NTSC_UpdateVideoText40; - static void (*ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; - static void (*ntscColorPixel)(int) = 0; //ntscColorSinglePixel; + static void (*g_pFunc_ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; + static void (*g_pFunc_ntscColorPixel)(int) = 0; //ntscColorSinglePixel; // Prototypes // prototype from CPU.h @@ -350,17 +350,17 @@ inline void updateVideoHorzEOL() //VIDEO_DRAW_ENDLINE(); if (g_nColorBurstPixels < 2) { - ntscMonoPixel(g_nLastColumnPixelNTSC); - ntscMonoPixel(0); - ntscMonoPixel(0); - ntscMonoPixel(0); + g_pFunc_ntscMonoPixel(g_nLastColumnPixelNTSC); + g_pFunc_ntscMonoPixel(0); + g_pFunc_ntscMonoPixel(0); + g_pFunc_ntscMonoPixel(0); } else { - ntscColorPixel(g_nLastColumnPixelNTSC); - ntscColorPixel(0); - ntscColorPixel(0); - ntscColorPixel(0); + g_pFunc_ntscColorPixel(g_nLastColumnPixelNTSC); + g_pFunc_ntscColorPixel(0); + g_pFunc_ntscColorPixel(0); + g_pFunc_ntscColorPixel(0); } } @@ -442,50 +442,50 @@ void VIDEO_DRAW_BITS( uint16_t bt ) // VIDEO_DRAW_BITS if (g_nColorBurstPixels < 2) { /* #1 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; /* #2 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; /* #3 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; /* #4 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; /* #5 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; /* #6 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; /* #7 of 7 */ - ntscMonoPixel(bt & 1); bt >>= 1; - ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFunc_ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; } else { /* #1 of 7 */ // abcd efgh ijkl mnop - ntscColorPixel(bt & 1); bt >>= 1; // 0abc defg hijk lmno - ntscColorPixel(bt & 1); bt >>= 1; // 00ab cdef ghi jklmn + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0abc defg hijk lmno + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 00ab cdef ghi jklmn /* #2 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; // 000a bcde fghi jklm - ntscColorPixel(bt & 1); bt >>= 1; // 0000 abcd efgh ijkl + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 000a bcde fghi jklm + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 abcd efgh ijkl /* #3 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0abc defg hijk - ntscColorPixel(bt & 1); bt >>= 1; // 0000 00ab cdef ghij + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0abc defg hijk + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 00ab cdef ghij /* #4 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; // 0000 000a bcde fghi - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 abcd efgh + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 000a bcde fghi + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 abcd efgh /* #5 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0abc defg - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 00ab cdef + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0abc defg + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 00ab cdef /* #6 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 000a bcde - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 abcd + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 000a bcde + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 abcd /* #7 of 7 */ - ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 0abc - ntscColorPixel(bt & 1); + g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 0abc + g_pFunc_ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC=bt & 1 ; bt >>= 1; // 0000 0000 0000 00ab } } @@ -785,9 +785,9 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) void NTSC_SetVideoTextMode( int cols ) { if( cols == 40 ) - g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; + g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; else - g_pNTSC_FuncVideoText = NTSC_UpdateVideoText80; + g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText80; } //=========================================================================== @@ -807,27 +807,27 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) if (bVideoModeFlags & VF_TEXT) { if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText80; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText80; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; } else if (bVideoModeFlags & VF_HIRES) { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleHires80; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleHires80; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleHires40; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleHires40; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoSingleHires40; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoSingleHires40; } else { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleLores80; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleLores80; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDoubleLores40; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleLores40; else - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoSingleLores40; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoSingleLores40; } } @@ -842,12 +842,12 @@ void NTSC_SetVideoStyle() // (int v, int s) case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: if (half) { - ntscMonoPixel = ntscMonoTVSinglePixel; - ntscColorPixel = ntscColorTVSinglePixel; + g_pFunc_ntscMonoPixel = ntscMonoTVSinglePixel; + g_pFunc_ntscColorPixel = ntscColorTVSinglePixel; } else { - ntscMonoPixel = ntscMonoTVDoublePixel; - ntscColorPixel = ntscColorTVDoublePixel; + g_pFunc_ntscMonoPixel = ntscMonoTVDoublePixel; + g_pFunc_ntscColorPixel = ntscColorTVDoublePixel; } break; @@ -855,12 +855,12 @@ void NTSC_SetVideoStyle() // (int v, int s) default: if (half) { - ntscMonoPixel = ntscMonoSinglePixel; - ntscColorPixel = ntscColorSinglePixel; + g_pFunc_ntscMonoPixel = ntscMonoSinglePixel; + g_pFunc_ntscColorPixel = ntscColorSinglePixel; } else { - ntscMonoPixel = ntscMonoDoublePixel; - ntscColorPixel = ntscColorDoublePixel; + g_pFunc_ntscMonoPixel = ntscMonoDoublePixel; + g_pFunc_ntscColorPixel = ntscColorDoublePixel; } break; @@ -871,10 +871,10 @@ void NTSC_SetVideoStyle() // (int v, int s) updateMonochromeColor( r, g, b ); // Custom Monochrome color if (half) { - ntscMonoPixel = ntscColorPixel = ntscMonoTVSinglePixel; + g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoTVSinglePixel; } else { - ntscMonoPixel = ntscColorPixel = ntscMonoTVDoublePixel; + g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoTVDoublePixel; } break; @@ -910,11 +910,11 @@ _mono: updateMonochromeColor( r, g, b ); // Custom Monochrome color if (half) { - ntscMonoPixel = ntscColorPixel = ntscMonoSinglePixel; + g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoSinglePixel; } else { - ntscMonoPixel = ntscColorPixel = ntscMonoDoublePixel; + g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoDoublePixel; } break; } @@ -927,7 +927,7 @@ void NTSC_UpdateVideoDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pNTSC_FuncVideoText( cycles6502 ); + g_pFunc_NTSCVideoUpdateText( cycles6502 ); return; } @@ -961,7 +961,7 @@ void NTSC_UpdateVideoDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pNTSC_FuncVideoText( cycles6502 ); + g_pFunc_NTSCVideoUpdateText( cycles6502 ); return; } @@ -1000,7 +1000,7 @@ void NTSC_UpdateVideoDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pNTSC_FuncVideoText( cycles6502 ); + g_pFunc_NTSCVideoUpdateText( cycles6502 ); return; } @@ -1034,7 +1034,7 @@ void NTSC_UpdateVideoDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pNTSC_FuncVideoText( cycles6502 ); + g_pFunc_NTSCVideoUpdateText( cycles6502 ); return; } @@ -1077,7 +1077,7 @@ void NTSC_UpdateVideoSingleHires40 (long cycles6502) if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pNTSC_FuncVideoText( cycles6502 ); + g_pFunc_NTSCVideoUpdateText( cycles6502 ); return; } @@ -1112,7 +1112,7 @@ void NTSC_UpdateVideoSingleLores40 (long cycles6502) if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pNTSC_FuncVideoText( cycles6502 ); + g_pFunc_NTSCVideoUpdateText( cycles6502 ); return; } @@ -1232,11 +1232,11 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit vbp0 = g_aNTSC_Lines[0]; // wsLines - ntscMonoPixel = ntscMonoSinglePixel ; - ntscColorPixel = ntscColorSinglePixel; + g_pFunc_ntscMonoPixel = ntscMonoSinglePixel ; + g_pFunc_ntscColorPixel = ntscColorSinglePixel; - g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40; - g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40; + g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; + g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; #if HGR_TEST_PATTERN // Michael -- Init HGR to almost all-possible-combinations @@ -1305,7 +1305,7 @@ int NTSC_VideoIsVbl () void NTSC_VideoUpdateCycles( long cycles ) { // if( !g_bFullSpeed ) -// g_pNTSC_FuncVideoUpdate( uElapsedCycles ); +// g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); // else for( ; cycles > 0; cycles-- ) { @@ -1322,7 +1322,7 @@ void NTSC_VideoUpdateCycles( long cycles ) } // Force full refresh - g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + g_pFunc_NTSCVideoUpdateGraphics( VIDEO_SCANNER_6502_CYCLES ); } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) diff --git a/source/NTSC.h b/source/NTSC.h index 116cae8e..7b16e887 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -5,7 +5,7 @@ extern uint16_t g_nVideoClockVert; extern uint16_t g_nVideoClockHorz; extern uint8_t* g_NTSC_pLines[384]; - extern void (* g_pNTSC_FuncVideoUpdate)(long); + extern void (* g_pFunc_NTSCVideoUpdateGraphics)(long); // Prototypes (Public) ________________________________________________ extern void NTSC_SetVideoTextMode( int cols ); diff --git a/source/Video.cpp b/source/Video.cpp index 058ce02e..5b3bf9a8 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1250,7 +1250,7 @@ void VideoRefreshScreen ( int bVideoModeFlags ) if( bVideoModeFlags ) { NTSC_SetVideoMode( bVideoModeFlags ); - g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES ); + g_pFunc_NTSCVideoUpdateGraphics( VIDEO_SCANNER_6502_CYCLES ); } // NTSC_BEGIN: wsVideoRefresh() From 88a7ab7b0b2c7c2624237eb1ab78e3bb23fe0127 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 02:45:47 -0800 Subject: [PATCH 023/121] Fix video configuration initialization order not being applied for 50% scan lines --- source/Applewin.cpp | 1 - source/NTSC.cpp | 7 +++---- source/Video.cpp | 8 +------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index e22cfec3..da9542af 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -432,7 +432,6 @@ void LoadConfiguration(void) REGLOAD(TEXT(REGVALUE_ENHANCE_DISK_SPEED),(DWORD *)&enhancedisk); Config_Load_Video(); - VideoReinitialize(); REGLOAD(TEXT("Uthernet Active") ,(DWORD *)&tfe_enabled); diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 96820764..b723965a 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1232,12 +1232,11 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit vbp0 = g_aNTSC_Lines[0]; // wsLines - g_pFunc_ntscMonoPixel = ntscMonoSinglePixel ; - g_pFunc_ntscColorPixel = ntscColorSinglePixel; - - g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; + g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; + VideoReinitialize(); // Setup g_pFunc_ntsc*Pixel() + #if HGR_TEST_PATTERN // Michael -- Init HGR to almost all-possible-combinations // CALL-151 diff --git a/source/Video.cpp b/source/Video.cpp index 5b3bf9a8..c36ff346 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -378,7 +378,6 @@ void VideoInitialize () g_pFramebufferinfo->bmiHeader.biClrUsed = 0; NTSC_VideoCreateDIBSection(); -// VideoReinitialize(); // Can't call here since Config_Video_Load() hasn't been called yet } //=========================================================================== @@ -1197,7 +1196,7 @@ void VideoRedrawScreen () { g_VideoForceFullRedraw = 1; - VideoRefreshScreen( g_uVideoMode ); //g_uVideoMode ); + VideoRefreshScreen( g_uVideoMode ); } //=========================================================================== @@ -1276,11 +1275,6 @@ void VideoRefreshScreen ( int bVideoModeFlags ) // NTSC_END } -//=========================================================================== -//void _Video_RedrawScreen( VideoUpdateFuncPtr_t pfUpdate, bool bMixed ) -// FrameReleaseVideoDC(); -// SetLastDrawnImage(); - //=========================================================================== void VideoReinitialize () { From 9f32d59ae7c249bb7e4011551814e1c32d9a46b8 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 09:40:36 -0800 Subject: [PATCH 024/121] Add WIP palette PAL and RGB values --- source/NTSC.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index b723965a..97ec3156 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -63,6 +63,103 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define HGR_TEST_PATTERN 0 +// Types + + struct ColorSpace_PAL_t // Phase Amplitute Luma + { + float phase; + float amp; + float luma; + }; + + struct ColorSpace_YIQ_t + { + float y, i, q; + }; + + struct bgra_t + { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; + }; + struct rgba_t + { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + struct ColorSpace_BGRA_t + { + union + { + uint32_t n; + bgra_t bgra; + rgba_t rgba; + }; + }; + + /* + http://www.kreativekorp.com/miscpages/a2info/munafo.shtml + + "Primary" lo-res colors + Color GR Duty cycle Phase + ====================================== + Red COLOR=1 45 to 135 90 + Dark-blue COLOR=2 315 to 45 0 + Dark-green COLOR=4 225 to 315 270 + Brown COLOR=8 135 to 225 180 + */ + ColorSpace_PAL_t aPaletteYIQ[ 16 ] = + { // Lo Hi Dh + { 0, 0, 0 } // 0 0 Black + ,{ 90, 60, 25 } // 1 1 Red + ,{ 0, 60, 25 } // 2 8 Dark Blue + ,{ 45,100, 50 } // 3 2 9 Purple + ,{270, 60, 25 } // 4 Dark Green + ,{ 0, 0, 50 } // 5 Grey + ,{315,100, 50 } // 6 Medium Blue + ,{ 0, 60, 75 } // 7 Light Blue + ,{180, 60, 25 } // 8 Brown + ,{135,100, 50 } // 9 Orange + ,{ 0, 0, 50 } // 10 + ,{ 90, 60, 75 } // 11 Pink + ,{225,100, 50 } // 12 Light Green + ,{180, 60, 75 } // 13 Yellow + ,{270, 60, 75} // 14 Aqua + ,{ 0, 0,100 } // 15 White + }; + +// purple HCOLOR=2 45 100 50 255 68 253 +// orange HCOLOR=5 135 100 50 255 106 60 +// green HCOLOR=1 225 100 50 20 245 60 +// blue HCOLOR=6 315 100 50 20 207 253 + + rgba_t aPaletteRGB[ 16 ] = + { + { 0, 0, 0 } // 0 + ,{ 227, 30, 96 } // 1 + ,{ 96, 78, 189 } // 2 + ,{ 255, 68, 253 } // 3 + ,{ 0, 163, 96 } // 4 + ,{ 156, 156, 156 } // 5 + ,{ 20, 207, 253 } // 6 + ,{ 208, 195, 255 } // 7 + ,{ 96, 114, 3 } // 8 + ,{ 255, 106, 60 } // 9 + ,{ 156, 156, 156 } // 10 + ,{ 255, 160, 208 } // 11 + ,{ 20, 245, 60 } // 12 + ,{ 208, 221, 141 } // 13 + ,{ 114, 255, 208 } // 14 + ,{ 255, 255, 255 } // 15 + }; + + + // Globals (Public) ___________________________________________________ uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262 uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible From ccb5b50f6d027a41bb56828c776da1a3a238d55c Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 11:46:57 -0800 Subject: [PATCH 025/121] Cleanup: convert macros that update the framebuffer to inline funcs and make them more readable, convert NTSC lookup tables to bgra --- source/NTSC.cpp | 247 +++++++++++++++++++++++++++++++----------------- source/NTSC.h | 4 +- 2 files changed, 162 insertions(+), 89 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 97ec3156..b88ebf93 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -84,6 +84,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA uint8_t r; uint8_t a; }; + struct rgba_t { uint8_t r; @@ -185,18 +186,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ]; - unsigned char * g_aNTSC_Lines[384]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + + bgra_t *g_pVideoAddress; + bgra_t *g_aNTSC_Lines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 static unsigned g_nTextFlashCounter = 0; static uint16_t g_nTextFlashMask = 0; - static unsigned g_aPixelMaskGR[16]; + static unsigned g_aPixelMaskGR [ 16]; static uint16_t g_aPixelDoubleMaskHGR[128]; // hgrbits -> g_aPixelDoubleMaskHGR: 7-bit mono 280 pixels to 560 pixel doubling #define UpdateVideoAddressTXT() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] + g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400)) #define UpdateVideoAddressHGR() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)) // BUG? g_pHorzClockOffset - static unsigned char *vbp0; static int g_nLastColumnPixelNTSC; static int g_nColorBurstPixels; @@ -206,24 +208,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define NTSC_NUM_PHASES 4 #define NTSC_NUM_SEQUENCES 4096 - enum ColorChannel - { // Win32 DIB: BGRA format - _B = 0, - _G = 1, - _R = 2, - _A = 3, - NUM_COLOR_CHANNELS = 4 - }; - static unsigned char g_aNTSCMonoMonitor [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; - static unsigned char g_aNTSCColorMonitor [NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; - static unsigned char g_aNTSCMonoTelevision [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; - static unsigned char g_aNTSCColorTelevision[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + const uint32_t ALPHA32_MASK = 0xFF000000; // aarrggbb + + static bgra_t g_aNTSCMonoMonitor [NTSC_NUM_SEQUENCES]; + static bgra_t g_aNTSCColorMonitor [NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; + static bgra_t g_aNTSCMonoTelevision [NTSC_NUM_SEQUENCES]; + static bgra_t g_aNTSCColorTelevision[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; // g_aNTSCMonoMonitor * g_nMonochromeRGB -> g_aNTSCMonoMonitorCustom // g_aNTSCMonoTelevision * g_nMonochromeRGB -> g_aNTSCMonoTelevisionCustom - static unsigned char g_aNTSCMonoMonitorCustom [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; - static unsigned char g_aNTSCMonoTelevisionCustom [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS]; + static bgra_t g_aNTSCMonoMonitorCustom [NTSC_NUM_SEQUENCES]; + static bgra_t g_aNTSCMonoTelevisionCustom [NTSC_NUM_SEQUENCES]; #define NUM_SIGZEROS 2 #define NUM_SIGPOLES 2 @@ -374,7 +370,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; - static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; + static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; void (* g_pFunc_NTSCVideoUpdateGraphics)(long) = 0; // NTSC_UpdateVideoText40; static void (*g_pFunc_ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; @@ -473,7 +469,7 @@ inline void updateVideoHorzEOL() if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { - vbp0 = g_aNTSC_Lines[2*g_nVideoClockVert]; + g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; @@ -481,56 +477,135 @@ inline void updateVideoHorzEOL() } } -#define SINGLE_SCANLINE_MONITOR(signal,table) \ +#if 0 +#define updateFramebufferMonitorSingleScanline(signal,table) \ do { \ - unsigned int *cp, *mp; \ + uint32_t *cp, *mp; \ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ - *((unsigned int *)vbp0) = *cp; \ - mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ - *mp = ((*cp & 0x00fcfcfc) >> 2) + 0xff000000; \ - vbp0 += 4; \ + cp = (uint32_t*) &table[g_nSignalBitsNTSC]; \ + *(uint32_t*)g_pVideoAddress = *cp; \ + mp = (uint32_t*)(g_pVideoAddress - FRAMEBUFFER_W); \ + *mp = ((*cp & 0x00fcfcfc) >> 2) | ALPHA32_MASK; \ + g_pVideoAddress++; \ } while(0) -#define SINGLE_SCANLINE_TELEVISION(signal,table) \ +#define updateFramebufferTelevisionSingleScanline(signal,table) \ do { \ - unsigned int ntscp, prevp, betwp; \ - unsigned int *prevlin, *between; \ + uint32_t ntscp, prevp, betwp; \ + uint32_t *prevlin, *between; \ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ - between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ - ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ + prevlin = (uint32_t*)(g_pVideoAddress + 2*FRAMEBUFFER_W); \ + between = (uint32_t*)(g_pVideoAddress + 1*FRAMEBUFFER_W); \ + ntscp = *(uint32_t*) &table[g_nSignalBitsNTSC]; /* raw current NTSC color */ \ prevp = *prevlin; \ betwp = ntscp - ((ntscp & 0x00fcfcfc) >> 2); \ - *between = betwp | 0xff000000; \ - *((unsigned int *)vbp0) = ntscp; \ - vbp0 += 4; \ + *between = betwp | ALPHA32_MASK; \ + *(uint32_t*)g_pVideoAddress = ntscp; \ + g_pVideoAddress++; \ } while(0) -#define DOUBLE_SCANLINE_MONITOR(signal,table) \ +#define updateFramebufferMonitorDoubleScanline(signal,table) \ do { \ - unsigned int *cp, *mp; \ + uint32_t *cp, *mp; \ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \ - mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \ - *((unsigned int *)vbp0) = *mp = *cp; \ - vbp0 += 4; \ + cp = (uint32_t*) &table[g_nSignalBitsNTSC]; \ + mp = (uint32_t*)(g_pVideoAddress - FRAMEBUFFER_W); \ + *(uint32_t*)g_pVideoAddress = *mp = *cp; \ + g_pVideoAddress++; \ } while(0) -#define DOUBLE_SCANLINE_TELEVISION(signal,table) \ +#define updateFramebufferTelevisionDoubleScanline(signal,table) \ do { \ - unsigned int ntscp, prevp, betwp; \ - unsigned int *prevlin, *between; \ + uint32_t ntscp, prevp, betwp; \ + uint32_t *prevlin, *between; \ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \ - prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \ - between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \ - ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \ + prevlin = (uint32_t*)(g_pVideoAddress + 2*FRAMEBUFFER_W); \ + between = (uint32_t*)(g_pVideoAddress + 1*FRAMEBUFFER_W); \ + ntscp = *(uint32_t*) &table[g_nSignalBitsNTSC]; /* raw current NTSC color */ \ prevp = *prevlin; \ betwp = ((ntscp & 0x00fefefe) >> 1) + ((prevp & 0x00fefefe) >> 1); \ - *between = betwp | 0xff000000; \ - *((unsigned int *)vbp0) = ntscp; \ - vbp0 += 4; \ + *between = betwp | ALPHA32_MASK; \ + *(uint32_t*)g_pVideoAddress = ntscp; \ + g_pVideoAddress++; \ } while(0) +#else + +inline uint32_t* getScanlineNext1Address() +{ + return (uint32_t*) (g_pVideoAddress - 1*FRAMEBUFFER_W); +} + +inline uint32_t* getScanlinePrev1Address() +{ + return (uint32_t*) (g_pVideoAddress + 1*FRAMEBUFFER_W); +} + +inline uint32_t* getScanlinePrev2Address() +{ + return (uint32_t*) (g_pVideoAddress + 2*FRAMEBUFFER_W); +} + +uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) +{ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 14-bit + return *(uint32_t*) &pTable[ g_nSignalBitsNTSC ]; +} + +inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ) +{ + /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine1Address = getScanlineNext1Address(); + const uint32_t color0 = getScanlineColor( signal, pTable ); + const uint32_t color1 = ((color0 & 0x00fcfcfc) >> 2); // 25% Blend (original) +// const uint32_t color1 = ((color0 & 0x00fefefe) >> 1); // 50% Blend -- looks OK most of the time; Archon looks poor + + /* */ *pLine1Address = color1 | ALPHA32_MASK; + /* */ *pLine0Address = color0; + /* */ g_pVideoAddress++; +} + +inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ) +{ + /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine1Address = getScanlineNext1Address(); + const uint32_t color0 = getScanlineColor( signal, pTable ); + + /* */ *pLine1Address = color0; + /* */ *pLine0Address = color0; + /* */ g_pVideoAddress++; +} + +inline void updateFramebufferTelevisionSingleScanline( uint16_t signal, bgra_t *pTable ) +{ + /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine1Address = getScanlinePrev1Address(); + /* */ uint32_t *pLine2Address = getScanlinePrev2Address(); + + const uint32_t color0 = getScanlineColor( signal, pTable ); + const uint32_t color2 = *pLine2Address; + const uint32_t color1 = color0 - ((color0 & 0x00fcfcfc) >> 2); + + /* */ *pLine1Address = color1 | ALPHA32_MASK; + /* */ *pLine0Address = color0; + /* */ g_pVideoAddress++; +} + +inline void updateFramebufferTelevisionDoubleScanline( uint16_t signal, bgra_t *pTable ) +{ + /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine1Address = getScanlinePrev1Address(); + const uint32_t *pLine2Address = getScanlinePrev2Address(); + + const uint32_t color0 = getScanlineColor( signal, pTable ); + const uint32_t color2 = *pLine2Address; + const uint32_t color1 = ((color0 & 0x00fefefe) >> 1) + ((color2 & 0x00fefefe) >> 1); // 50% Blend + + /* */ *pLine1Address = color1 | ALPHA32_MASK; + /* */ *pLine0Address = color0; + /* */ g_pVideoAddress++; +} + +#endif //=========================================================================== inline @@ -742,16 +817,16 @@ static void init_chroma_phase_table (void) } // samples brightness = clampZeroOne( (float)z ); - g_aNTSCMonoMonitor[s][_B] = (uint8_t)(brightness * 255); - g_aNTSCMonoMonitor[s][_G] = (uint8_t)(brightness * 255); - g_aNTSCMonoMonitor[s][_R] = (uint8_t)(brightness * 255); - g_aNTSCMonoMonitor[s][_A] = 255; + g_aNTSCMonoMonitor[s].b = (uint8_t)(brightness * 255); + g_aNTSCMonoMonitor[s].g = (uint8_t)(brightness * 255); + g_aNTSCMonoMonitor[s].r = (uint8_t)(brightness * 255); + g_aNTSCMonoMonitor[s].a = 255; brightness = clampZeroOne( (float)y1); - g_aNTSCMonoTelevision[s][_B] = (uint8_t)(brightness * 255); - g_aNTSCMonoTelevision[s][_G] = (uint8_t)(brightness * 255); - g_aNTSCMonoTelevision[s][_R] = (uint8_t)(brightness * 255); - g_aNTSCMonoTelevision[s][_A] = 255; + g_aNTSCMonoTelevision[s].b = (uint8_t)(brightness * 255); + g_aNTSCMonoTelevision[s].g = (uint8_t)(brightness * 255); + g_aNTSCMonoTelevision[s].r = (uint8_t)(brightness * 255); + g_aNTSCMonoTelevision[s].a = 255; /* YI'V' to RGB @@ -788,10 +863,10 @@ static void init_chroma_phase_table (void) g32 = clampZeroOne( (float)g64); r32 = clampZeroOne( (float)r64); - g_aNTSCColorMonitor[phase][s][_B] = (uint8_t)(b32 * 255); - g_aNTSCColorMonitor[phase][s][_G] = (uint8_t)(g32 * 255); - g_aNTSCColorMonitor[phase][s][_R] = (uint8_t)(r32 * 255); - g_aNTSCColorMonitor[phase][s][_A] = 255; + g_aNTSCColorMonitor[phase][s].b = (uint8_t)(b32 * 255); + g_aNTSCColorMonitor[phase][s].g = (uint8_t)(g32 * 255); + g_aNTSCColorMonitor[phase][s].r = (uint8_t)(r32 * 255); + g_aNTSCColorMonitor[phase][s].a = 255; r64 = y1 + (I_TO_R * i) + (Q_TO_R * q); g64 = y1 + (I_TO_G * i) + (Q_TO_G * q); @@ -801,10 +876,10 @@ static void init_chroma_phase_table (void) g32 = clampZeroOne( (float)g64 ); r32 = clampZeroOne( (float)r64 ); - g_aNTSCColorTelevision[phase][s][_B] = (uint8_t)(b32 * 255); - g_aNTSCColorTelevision[phase][s][_G] = (uint8_t)(g32 * 255); - g_aNTSCColorTelevision[phase][s][_R] = (uint8_t)(r32 * 255); - g_aNTSCColorTelevision[phase][s][_A] = 255; + g_aNTSCColorTelevision[phase][s].b = (uint8_t)(b32 * 255); + g_aNTSCColorTelevision[phase][s].g = (uint8_t)(g32 * 255); + g_aNTSCColorTelevision[phase][s].r = (uint8_t)(r32 * 255); + g_aNTSCColorTelevision[phase][s].a = 255; } } } @@ -812,53 +887,53 @@ static void init_chroma_phase_table (void) //=========================================================================== static void ntscColorTVSinglePixel (int compositeSignal) { - SINGLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + updateFramebufferTelevisionSingleScanline(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscColorTVDoublePixel (int compositeSignal) { - DOUBLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + updateFramebufferTelevisionDoubleScanline(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscColorSinglePixel (int compositeSignal) { - SINGLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateFramebufferMonitorSingleScanline(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscColorDoublePixel (int compositeSignal) { - DOUBLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateFramebufferMonitorDoubleScanline(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscMonoSinglePixel (int compositeSignal) { - SINGLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCMonoMonitorCustom); + updateFramebufferMonitorSingleScanline(compositeSignal, g_aNTSCMonoMonitorCustom); } //=========================================================================== static void ntscMonoDoublePixel (int compositeSignal) { - DOUBLE_SCANLINE_MONITOR(compositeSignal, g_aNTSCMonoMonitorCustom); + updateFramebufferMonitorDoubleScanline(compositeSignal, g_aNTSCMonoMonitorCustom); } //=========================================================================== static void ntscMonoTVSinglePixel (int compositeSignal) { - SINGLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCMonoTelevisionCustom); + updateFramebufferTelevisionSingleScanline(compositeSignal, g_aNTSCMonoTelevisionCustom); } //=========================================================================== static void ntscMonoTVDoublePixel (int compositeSignal) { - DOUBLE_SCANLINE_TELEVISION(compositeSignal, g_aNTSCMonoTelevisionCustom); + updateFramebufferTelevisionDoubleScanline(compositeSignal, g_aNTSCMonoTelevisionCustom); } //=========================================================================== @@ -866,15 +941,15 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) { for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ ) { - g_aNTSCMonoMonitorCustom[ iSample ][ _B ] = (g_aNTSCMonoMonitor[ iSample ][_B] * b) >> 8; - g_aNTSCMonoMonitorCustom[ iSample ][ _G ] = (g_aNTSCMonoMonitor[ iSample ][_G] * g) >> 8; - g_aNTSCMonoMonitorCustom[ iSample ][ _R ] = (g_aNTSCMonoMonitor[ iSample ][_R] * r) >> 8; - g_aNTSCMonoMonitorCustom[ iSample ][ _A ] = 0xFF; + g_aNTSCMonoMonitorCustom[ iSample ].b = (g_aNTSCMonoMonitor[ iSample ].b * b) >> 8; + g_aNTSCMonoMonitorCustom[ iSample ].g = (g_aNTSCMonoMonitor[ iSample ].g * g) >> 8; + g_aNTSCMonoMonitorCustom[ iSample ].r = (g_aNTSCMonoMonitor[ iSample ].r * r) >> 8; + g_aNTSCMonoMonitorCustom[ iSample ].a = 0xFF; - g_aNTSCMonoTelevisionCustom[ iSample ][ _B ] = (g_aNTSCMonoTelevision[ iSample ][_B] * b) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ][ _G ] = (g_aNTSCMonoTelevision[ iSample ][_G] * g) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ][ _R ] = (g_aNTSCMonoTelevision[ iSample ][_R] * r) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ][ _A ] = 0xFF; + g_aNTSCMonoTelevisionCustom[ iSample ].b = (g_aNTSCMonoTelevision[ iSample ].b * b) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ].g = (g_aNTSCMonoTelevision[ iSample ].g * g) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ].r = (g_aNTSCMonoTelevision[ iSample ].r * r) >> 8; + g_aNTSCMonoTelevisionCustom[ iSample ].a = 0xFF; } } @@ -1324,10 +1399,10 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit init_chroma_phase_table(); updateMonochromeColor( 0xFF, 0xFF, 0xFF ); - for (int y = 0; y < 384; y++) - g_aNTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80; + for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) + g_aNTSC_Lines[y] = (bgra_t*)(g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80); - vbp0 = g_aNTSC_Lines[0]; // wsLines + g_pVideoAddress = g_aNTSC_Lines[0]; // wsLines g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; @@ -1423,7 +1498,7 @@ void NTSC_VideoUpdateCycles( long cycles ) if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { - vbp0 = g_aNTSC_Lines[2*g_nVideoClockVert]; + g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; diff --git a/source/NTSC.h b/source/NTSC.h index 7b16e887..2cd30486 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -1,11 +1,9 @@ #define VIDEO_SCANNER_6502_CYCLES 17030 // Globals (Public) - extern uint16_t g_nVideoClockVert; extern uint16_t g_nVideoClockHorz; - extern uint8_t* g_NTSC_pLines[384]; - extern void (* g_pFunc_NTSCVideoUpdateGraphics)(long); + extern void (* g_pFunc_NTSCVideoUpdateGraphics)(long); // Prototypes (Public) ________________________________________________ extern void NTSC_SetVideoTextMode( int cols ); From 5288623f6e6d22f7aed1d0806a41af6210483af0 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 11:59:49 -0800 Subject: [PATCH 026/121] misc. cleanup alignment --- source/NTSC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index b88ebf93..a9c86149 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1027,7 +1027,7 @@ void NTSC_SetVideoStyle() // (int v, int s) default: if (half) { - g_pFunc_ntscMonoPixel = ntscMonoSinglePixel; + g_pFunc_ntscMonoPixel = ntscMonoSinglePixel; g_pFunc_ntscColorPixel = ntscColorSinglePixel; } else { From 421db69b9e78ccf5c43f38d4504545cc98b679fc Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 12:12:22 -0800 Subject: [PATCH 027/121] Cleanup brga table tnames --- source/NTSC.cpp | 90 ++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index a9c86149..311f16cf 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -209,17 +209,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define NTSC_NUM_PHASES 4 #define NTSC_NUM_SEQUENCES 4096 - const uint32_t ALPHA32_MASK = 0xFF000000; // aarrggbb + const uint32_t ALPHA32_MASK = 0xFF000000; // Win32: aarrggbb - static bgra_t g_aNTSCMonoMonitor [NTSC_NUM_SEQUENCES]; - static bgra_t g_aNTSCColorMonitor [NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; - static bgra_t g_aNTSCMonoTelevision [NTSC_NUM_SEQUENCES]; - static bgra_t g_aNTSCColorTelevision[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; + static bgra_t g_aBnWMonitor [NTSC_NUM_SEQUENCES]; + static bgra_t g_aHueMonitor[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; + static bgra_t g_aBnwColorTV [NTSC_NUM_SEQUENCES]; + static bgra_t g_aHueColorTV[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; -// g_aNTSCMonoMonitor * g_nMonochromeRGB -> g_aNTSCMonoMonitorCustom -// g_aNTSCMonoTelevision * g_nMonochromeRGB -> g_aNTSCMonoTelevisionCustom - static bgra_t g_aNTSCMonoMonitorCustom [NTSC_NUM_SEQUENCES]; - static bgra_t g_aNTSCMonoTelevisionCustom [NTSC_NUM_SEQUENCES]; + // g_aBnWMonitor * g_nMonochromeRGB -> g_aBnWMonitorCustom + // g_aBnwColorTV * g_nMonochromeRGB -> g_aBnWColorTVCustom + static bgra_t g_aBnWMonitorCustom [NTSC_NUM_SEQUENCES]; + static bgra_t g_aBnWColorTVCustom [NTSC_NUM_SEQUENCES]; #define NUM_SIGZEROS 2 #define NUM_SIGPOLES 2 @@ -489,7 +489,7 @@ inline void updateVideoHorzEOL() g_pVideoAddress++; \ } while(0) -#define updateFramebufferTelevisionSingleScanline(signal,table) \ +#define updateFramebufferColorTVSingleScanline(signal,table) \ do { \ uint32_t ntscp, prevp, betwp; \ uint32_t *prevlin, *between; \ @@ -514,7 +514,7 @@ inline void updateVideoHorzEOL() g_pVideoAddress++; \ } while(0) -#define updateFramebufferTelevisionDoubleScanline(signal,table) \ +#define updateFramebufferColorTVDoubleScanline(signal,table) \ do { \ uint32_t ntscp, prevp, betwp; \ uint32_t *prevlin, *between; \ @@ -575,7 +575,7 @@ inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTa /* */ g_pVideoAddress++; } -inline void updateFramebufferTelevisionSingleScanline( uint16_t signal, bgra_t *pTable ) +inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ) { /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; /* */ uint32_t *pLine1Address = getScanlinePrev1Address(); @@ -590,7 +590,7 @@ inline void updateFramebufferTelevisionSingleScanline( uint16_t signal, bgra_t * /* */ g_pVideoAddress++; } -inline void updateFramebufferTelevisionDoubleScanline( uint16_t signal, bgra_t *pTable ) +inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ) { /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; /* */ uint32_t *pLine1Address = getScanlinePrev1Address(); @@ -817,16 +817,16 @@ static void init_chroma_phase_table (void) } // samples brightness = clampZeroOne( (float)z ); - g_aNTSCMonoMonitor[s].b = (uint8_t)(brightness * 255); - g_aNTSCMonoMonitor[s].g = (uint8_t)(brightness * 255); - g_aNTSCMonoMonitor[s].r = (uint8_t)(brightness * 255); - g_aNTSCMonoMonitor[s].a = 255; + g_aBnWMonitor[s].b = (uint8_t)(brightness * 255); + g_aBnWMonitor[s].g = (uint8_t)(brightness * 255); + g_aBnWMonitor[s].r = (uint8_t)(brightness * 255); + g_aBnWMonitor[s].a = 255; brightness = clampZeroOne( (float)y1); - g_aNTSCMonoTelevision[s].b = (uint8_t)(brightness * 255); - g_aNTSCMonoTelevision[s].g = (uint8_t)(brightness * 255); - g_aNTSCMonoTelevision[s].r = (uint8_t)(brightness * 255); - g_aNTSCMonoTelevision[s].a = 255; + g_aBnwColorTV[s].b = (uint8_t)(brightness * 255); + g_aBnwColorTV[s].g = (uint8_t)(brightness * 255); + g_aBnwColorTV[s].r = (uint8_t)(brightness * 255); + g_aBnwColorTV[s].a = 255; /* YI'V' to RGB @@ -863,10 +863,10 @@ static void init_chroma_phase_table (void) g32 = clampZeroOne( (float)g64); r32 = clampZeroOne( (float)r64); - g_aNTSCColorMonitor[phase][s].b = (uint8_t)(b32 * 255); - g_aNTSCColorMonitor[phase][s].g = (uint8_t)(g32 * 255); - g_aNTSCColorMonitor[phase][s].r = (uint8_t)(r32 * 255); - g_aNTSCColorMonitor[phase][s].a = 255; + g_aHueMonitor[phase][s].b = (uint8_t)(b32 * 255); + g_aHueMonitor[phase][s].g = (uint8_t)(g32 * 255); + g_aHueMonitor[phase][s].r = (uint8_t)(r32 * 255); + g_aHueMonitor[phase][s].a = 255; r64 = y1 + (I_TO_R * i) + (Q_TO_R * q); g64 = y1 + (I_TO_G * i) + (Q_TO_G * q); @@ -876,10 +876,10 @@ static void init_chroma_phase_table (void) g32 = clampZeroOne( (float)g64 ); r32 = clampZeroOne( (float)r64 ); - g_aNTSCColorTelevision[phase][s].b = (uint8_t)(b32 * 255); - g_aNTSCColorTelevision[phase][s].g = (uint8_t)(g32 * 255); - g_aNTSCColorTelevision[phase][s].r = (uint8_t)(r32 * 255); - g_aNTSCColorTelevision[phase][s].a = 255; + g_aHueColorTV[phase][s].b = (uint8_t)(b32 * 255); + g_aHueColorTV[phase][s].g = (uint8_t)(g32 * 255); + g_aHueColorTV[phase][s].r = (uint8_t)(r32 * 255); + g_aHueColorTV[phase][s].a = 255; } } } @@ -887,53 +887,53 @@ static void init_chroma_phase_table (void) //=========================================================================== static void ntscColorTVSinglePixel (int compositeSignal) { - updateFramebufferTelevisionSingleScanline(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + updateFramebufferColorTVSingleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscColorTVDoublePixel (int compositeSignal) { - updateFramebufferTelevisionDoubleScanline(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]); + updateFramebufferColorTVDoubleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscColorSinglePixel (int compositeSignal) { - updateFramebufferMonitorSingleScanline(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateFramebufferMonitorSingleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscColorDoublePixel (int compositeSignal) { - updateFramebufferMonitorDoubleScanline(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]); + updateFramebufferMonitorDoubleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== static void ntscMonoSinglePixel (int compositeSignal) { - updateFramebufferMonitorSingleScanline(compositeSignal, g_aNTSCMonoMonitorCustom); + updateFramebufferMonitorSingleScanline(compositeSignal, g_aBnWMonitorCustom); } //=========================================================================== static void ntscMonoDoublePixel (int compositeSignal) { - updateFramebufferMonitorDoubleScanline(compositeSignal, g_aNTSCMonoMonitorCustom); + updateFramebufferMonitorDoubleScanline(compositeSignal, g_aBnWMonitorCustom); } //=========================================================================== static void ntscMonoTVSinglePixel (int compositeSignal) { - updateFramebufferTelevisionSingleScanline(compositeSignal, g_aNTSCMonoTelevisionCustom); + updateFramebufferColorTVSingleScanline(compositeSignal, g_aBnWColorTVCustom); } //=========================================================================== static void ntscMonoTVDoublePixel (int compositeSignal) { - updateFramebufferTelevisionDoubleScanline(compositeSignal, g_aNTSCMonoTelevisionCustom); + updateFramebufferColorTVDoubleScanline(compositeSignal, g_aBnWColorTVCustom); } //=========================================================================== @@ -941,15 +941,15 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) { for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ ) { - g_aNTSCMonoMonitorCustom[ iSample ].b = (g_aNTSCMonoMonitor[ iSample ].b * b) >> 8; - g_aNTSCMonoMonitorCustom[ iSample ].g = (g_aNTSCMonoMonitor[ iSample ].g * g) >> 8; - g_aNTSCMonoMonitorCustom[ iSample ].r = (g_aNTSCMonoMonitor[ iSample ].r * r) >> 8; - g_aNTSCMonoMonitorCustom[ iSample ].a = 0xFF; + g_aBnWMonitorCustom[ iSample ].b = (g_aBnWMonitor[ iSample ].b * b) >> 8; + g_aBnWMonitorCustom[ iSample ].g = (g_aBnWMonitor[ iSample ].g * g) >> 8; + g_aBnWMonitorCustom[ iSample ].r = (g_aBnWMonitor[ iSample ].r * r) >> 8; + g_aBnWMonitorCustom[ iSample ].a = 0xFF; - g_aNTSCMonoTelevisionCustom[ iSample ].b = (g_aNTSCMonoTelevision[ iSample ].b * b) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ].g = (g_aNTSCMonoTelevision[ iSample ].g * g) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ].r = (g_aNTSCMonoTelevision[ iSample ].r * r) >> 8; - g_aNTSCMonoTelevisionCustom[ iSample ].a = 0xFF; + g_aBnWColorTVCustom[ iSample ].b = (g_aBnwColorTV[ iSample ].b * b) >> 8; + g_aBnWColorTVCustom[ iSample ].g = (g_aBnwColorTV[ iSample ].g * g) >> 8; + g_aBnWColorTVCustom[ iSample ].r = (g_aBnwColorTV[ iSample ].r * r) >> 8; + g_aBnWColorTVCustom[ iSample ].a = 0xFF; } } From a09c64e5f5ecdebffde9659e90b5dc94cbf22b8b Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 12:23:28 -0800 Subject: [PATCH 028/121] Add Alpha Watermark so we can track bugs --- source/Video.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source/Video.cpp b/source/Video.cpp index c36ff346..33271c26 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1132,6 +1132,23 @@ void VideoDisplayLogo () DRAWVERSION( 0, -356*scale,RGB(0xFF,0x00,0xFF)); #endif +// NTSC Alpha Version + DeleteObject(font); + font = CreateFontA( + -56,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, + VARIABLE_PITCH | 4 | FF_SWISS, + TEXT("Arial") + ); + SelectObject(hFrameDC,font); + sprintf( szVersion, "NTSC ALPHA v11" ); + xoff = 0; + yoff = 0; + DRAWVERSION( 2, -158*scale,RGB(0x00,0x00,0x00)); + DRAWVERSION( 1, -157*scale,RGB(0x00,0x00,0x00)); + DRAWVERSION( 0, -156*scale,RGB(0xFF,0x00,0xFF)); +// NTSC END + #undef DRAWVERSION FrameReleaseDC(); From d8fe5a470023b4a2c100b88e9b6fbf99ee4f5d04 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 17:24:55 -0800 Subject: [PATCH 029/121] Cleanup: cycles name --- source/NTSC.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 311f16cf..81d8351c 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -543,6 +543,7 @@ inline uint32_t* getScanlinePrev1Address() inline uint32_t* getScanlinePrev2Address() { return (uint32_t*) (g_pVideoAddress + 2*FRAMEBUFFER_W); + } uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) @@ -1343,11 +1344,11 @@ void NTSC_UpdateVideoText40 (long cycles6502) } //=========================================================================== -void NTSC_UpdateVideoText80 (long ticks) +void NTSC_UpdateVideoText80 (long cycles6502) { unsigned int ad; - for (; ticks; --ticks) + for (; cycles6502; --cycles6502) { UpdateVideoAddressTXT(); @@ -1384,7 +1385,7 @@ void NTSC_UpdateVideoText80 (long ticks) } //=========================================================================== -unsigned char NTSC_VideoByte (unsigned long cycle) +unsigned char NTSC_VideoByte (unsigned long cycles6502) { unsigned char * mem; mem = MemGetMainPtr(g_aHorzClockMemAddress[ g_nVideoClockHorz ]); @@ -1473,12 +1474,12 @@ int NTSC_VideoIsVbl () // Light-weight Video Clock Update //=========================================================================== -void NTSC_VideoUpdateCycles( long cycles ) +void NTSC_VideoUpdateCycles( long cycles6502 ) { // if( !g_bFullSpeed ) -// g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); +// g_pFunc_NTSCVideoUpdateGraphics( cycles6502 ); // else - for( ; cycles > 0; cycles-- ) + for( ; cycles6502 > 0; cycles6502-- ) { if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) { From d67f084bf3fb8fc96df41efa8f3e35cac81dbaec Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 17:38:48 -0800 Subject: [PATCH 030/121] Remove flicker from NTSC_VideoUpdateCycles() -- draw each scanline --- source/NTSC.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 81d8351c..6c204f67 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -376,6 +376,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void (*g_pFunc_ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; static void (*g_pFunc_ntscColorPixel)(int) = 0; //ntscColorSinglePixel; + typedef void (*Func_t)(long); + static Func_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; + // Prototypes // prototype from CPU.h //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles); @@ -1476,6 +1479,8 @@ int NTSC_VideoIsVbl () //=========================================================================== void NTSC_VideoUpdateCycles( long cycles6502 ) { + bool bRedraw = false; + // if( !g_bFullSpeed ) // g_pFunc_NTSCVideoUpdateGraphics( cycles6502 ); // else @@ -1492,13 +1497,13 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) g_nTextFlashCounter = 0; g_nTextFlashMask ^= -1; // 16-bits } - - // Force full refresh - g_pFunc_NTSCVideoUpdateGraphics( VIDEO_SCANNER_6502_CYCLES ); + bRedraw = true; } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { + g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFunc_NTSCVideoUpdateGraphics; + g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; @@ -1506,4 +1511,15 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) } } } + + if( bRedraw ) // Force full refresh + { + for( int y = 0; y < VIDEO_SCANNER_Y_DISPLAY; y++ ) + { + g_apFuncVideoUpdateScanline[ y ]( VIDEO_SCANNER_MAX_HORZ ); + } + + int nCyclesVBlank = (VIDEO_SCANNER_MAX_VERT - VIDEO_SCANNER_Y_DISPLAY) * VIDEO_SCANNER_MAX_HORZ; + g_pFunc_NTSCVideoUpdateGraphics( nCyclesVBlank ); + } } From c3470c6e6ffbd19c2382d7989f746463eb3d99d5 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 17:40:30 -0800 Subject: [PATCH 031/121] Cleanup: move PAL and RGB table --- source/NTSC.cpp | 114 ++++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 6c204f67..b81debfc 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -103,63 +103,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }; }; - /* - http://www.kreativekorp.com/miscpages/a2info/munafo.shtml - - "Primary" lo-res colors - Color GR Duty cycle Phase - ====================================== - Red COLOR=1 45 to 135 90 - Dark-blue COLOR=2 315 to 45 0 - Dark-green COLOR=4 225 to 315 270 - Brown COLOR=8 135 to 225 180 - */ - ColorSpace_PAL_t aPaletteYIQ[ 16 ] = - { // Lo Hi Dh - { 0, 0, 0 } // 0 0 Black - ,{ 90, 60, 25 } // 1 1 Red - ,{ 0, 60, 25 } // 2 8 Dark Blue - ,{ 45,100, 50 } // 3 2 9 Purple - ,{270, 60, 25 } // 4 Dark Green - ,{ 0, 0, 50 } // 5 Grey - ,{315,100, 50 } // 6 Medium Blue - ,{ 0, 60, 75 } // 7 Light Blue - ,{180, 60, 25 } // 8 Brown - ,{135,100, 50 } // 9 Orange - ,{ 0, 0, 50 } // 10 - ,{ 90, 60, 75 } // 11 Pink - ,{225,100, 50 } // 12 Light Green - ,{180, 60, 75 } // 13 Yellow - ,{270, 60, 75} // 14 Aqua - ,{ 0, 0,100 } // 15 White - }; - -// purple HCOLOR=2 45 100 50 255 68 253 -// orange HCOLOR=5 135 100 50 255 106 60 -// green HCOLOR=1 225 100 50 20 245 60 -// blue HCOLOR=6 315 100 50 20 207 253 - - rgba_t aPaletteRGB[ 16 ] = - { - { 0, 0, 0 } // 0 - ,{ 227, 30, 96 } // 1 - ,{ 96, 78, 189 } // 2 - ,{ 255, 68, 253 } // 3 - ,{ 0, 163, 96 } // 4 - ,{ 156, 156, 156 } // 5 - ,{ 20, 207, 253 } // 6 - ,{ 208, 195, 255 } // 7 - ,{ 96, 114, 3 } // 8 - ,{ 255, 106, 60 } // 9 - ,{ 156, 156, 156 } // 10 - ,{ 255, 160, 208 } // 11 - ,{ 20, 245, 60 } // 12 - ,{ 208, 221, 141 } // 13 - ,{ 114, 255, 208 } // 14 - ,{ 255, 255, 255 } // 15 - }; - - // Globals (Public) ___________________________________________________ uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262 @@ -368,6 +311,63 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} }; + /* + http://www.kreativekorp.com/miscpages/a2info/munafo.shtml + + "Primary" lo-res colors + Color GR Duty cycle Phase + ====================================== + Red COLOR=1 45 to 135 90 + Dark-blue COLOR=2 315 to 45 0 + Dark-green COLOR=4 225 to 315 270 + Brown COLOR=8 135 to 225 180 + */ + ColorSpace_PAL_t aPaletteYIQ[ 16 ] = + { // Lo Hi Dh + { 0, 0, 0 } // 0 0 Black + ,{ 90, 60, 25 } // 1 1 Red + ,{ 0, 60, 25 } // 2 8 Dark Blue + ,{ 45,100, 50 } // 3 2 9 Purple + ,{270, 60, 25 } // 4 Dark Green + ,{ 0, 0, 50 } // 5 Grey + ,{315,100, 50 } // 6 Medium Blue + ,{ 0, 60, 75 } // 7 Light Blue + ,{180, 60, 25 } // 8 Brown + ,{135,100, 50 } // 9 Orange + ,{ 0, 0, 50 } // 10 + ,{ 90, 60, 75 } // 11 Pink + ,{225,100, 50 } // 12 Light Green + ,{180, 60, 75 } // 13 Yellow + ,{270, 60, 75} // 14 Aqua + ,{ 0, 0,100 } // 15 White + }; + +// purple HCOLOR=2 45 100 50 255 68 253 +// orange HCOLOR=5 135 100 50 255 106 60 +// green HCOLOR=1 225 100 50 20 245 60 +// blue HCOLOR=6 315 100 50 20 207 253 + + rgba_t aPaletteRGB[ 16 ] = + { + { 0, 0, 0 } // 0 + ,{ 227, 30, 96 } // 1 + ,{ 96, 78, 189 } // 2 + ,{ 255, 68, 253 } // 3 + ,{ 0, 163, 96 } // 4 + ,{ 156, 156, 156 } // 5 + ,{ 20, 207, 253 } // 6 + ,{ 208, 195, 255 } // 7 + ,{ 96, 114, 3 } // 8 + ,{ 255, 106, 60 } // 9 + ,{ 156, 156, 156 } // 10 + ,{ 255, 160, 208 } // 11 + ,{ 20, 245, 60 } // 12 + ,{ 208, 221, 141 } // 13 + ,{ 114, 255, 208 } // 14 + ,{ 255, 255, 255 } // 15 + }; + + static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; From e98a0f5f7e79b82c79ababb2b3eaa59d0b437eed Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 17:56:16 -0800 Subject: [PATCH 032/121] Optimize rendering so it doesn't hog the CPU --- source/CPU/cpu6502.h | 5 +---- source/CPU/cpu65C02.h | 5 +---- source/CPU/cpu65d02.h | 5 +---- source/NTSC.cpp | 32 +++++++++++++++++--------------- source/NTSC.h | 4 ++-- source/Video.cpp | 6 +++--- 6 files changed, 25 insertions(+), 32 deletions(-) diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index 947334e5..3645242e 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -322,10 +322,7 @@ static DWORD Cpu6502 (DWORD uTotalCycles) // NTSC_BEGIN uElapsedCycles = uExecutedCycles - uPreviousCycles; - if( g_bFullSpeed ) - NTSC_VideoUpdateCycles( uElapsedCycles ); - else - g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); + NTSC_VideoUpdateCycles( uElapsedCycles ); // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index 545f44ab..a85e3c04 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -326,10 +326,7 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) // NTSC_BEGIN uElapsedCycles = uExecutedCycles - uPreviousCycles; - if( g_bFullSpeed ) - NTSC_VideoUpdateCycles( uElapsedCycles ); - else - g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); + NTSC_VideoUpdateCycles( uElapsedCycles ); // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index c082a6c1..bd55a933 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -655,10 +655,7 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) // NTSC_BEGIN uElapsedCycles = uExecutedCycles - uPreviousCycles; - if( g_bFullSpeed ) - NTSC_VideoUpdateCycles( uElapsedCycles ); - else - g_pFunc_NTSCVideoUpdateGraphics( uElapsedCycles ); + NTSC_VideoUpdateCycles( uElapsedCycles ); // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/NTSC.cpp b/source/NTSC.cpp index b81debfc..6c8a05c1 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -132,6 +132,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA bgra_t *g_pVideoAddress; bgra_t *g_aNTSC_Lines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; + + typedef void (*Func_t)(long); + static Func_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; + + static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; + void (* g_pFunc_NTSCVideoUpdateGraphics)(long) = 0; // NTSC_UpdateVideoText40; + + static void (*g_pFunc_ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; + static void (*g_pFunc_ntscColorPixel)(int) = 0; //ntscColorSinglePixel; + static unsigned g_nTextFlashCounter = 0; static uint16_t g_nTextFlashMask = 0; @@ -368,17 +379,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }; - static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; - - static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; - void (* g_pFunc_NTSCVideoUpdateGraphics)(long) = 0; // NTSC_UpdateVideoText40; - - static void (*g_pFunc_ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; - static void (*g_pFunc_ntscColorPixel)(int) = 0; //ntscColorSinglePixel; - - typedef void (*Func_t)(long); - static Func_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; - // Prototypes // prototype from CPU.h //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles); @@ -1479,11 +1479,15 @@ int NTSC_VideoIsVbl () //=========================================================================== void NTSC_VideoUpdateCycles( long cycles6502 ) { - bool bRedraw = false; + bool bRedraw = cycles6502 >= VIDEO_SCANNER_6502_CYCLES; -// if( !g_bFullSpeed ) +// if( g_bFullSpeed ) // g_pFunc_NTSCVideoUpdateGraphics( cycles6502 ); // else + + while( cycles6502 > VIDEO_SCANNER_6502_CYCLES ) + /* */ cycles6502 -= VIDEO_SCANNER_6502_CYCLES ; + for( ; cycles6502 > 0; cycles6502-- ) { if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) @@ -1515,9 +1519,7 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) if( bRedraw ) // Force full refresh { for( int y = 0; y < VIDEO_SCANNER_Y_DISPLAY; y++ ) - { g_apFuncVideoUpdateScanline[ y ]( VIDEO_SCANNER_MAX_HORZ ); - } int nCyclesVBlank = (VIDEO_SCANNER_MAX_VERT - VIDEO_SCANNER_Y_DISPLAY) * VIDEO_SCANNER_MAX_HORZ; g_pFunc_NTSCVideoUpdateGraphics( nCyclesVBlank ); diff --git a/source/NTSC.h b/source/NTSC.h index 2cd30486..f693d2cc 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -1,9 +1,9 @@ -#define VIDEO_SCANNER_6502_CYCLES 17030 +// Constants + const int VIDEO_SCANNER_6502_CYCLES = 17030; // Globals (Public) extern uint16_t g_nVideoClockVert; extern uint16_t g_nVideoClockHorz; - extern void (* g_pFunc_NTSCVideoUpdateGraphics)(long); // Prototypes (Public) ________________________________________________ extern void NTSC_SetVideoTextMode( int cols ); diff --git a/source/Video.cpp b/source/Video.cpp index 33271c26..e7bb4b3d 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1266,7 +1266,7 @@ void VideoRefreshScreen ( int bVideoModeFlags ) if( bVideoModeFlags ) { NTSC_SetVideoMode( bVideoModeFlags ); - g_pFunc_NTSCVideoUpdateGraphics( VIDEO_SCANNER_6502_CYCLES ); + NTSC_VideoUpdateCycles( VIDEO_SCANNER_6502_CYCLES ); } // NTSC_BEGIN: wsVideoRefresh() @@ -1341,7 +1341,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) // NTSC_BEGIN NTSC_SetVideoMode( g_uVideoMode ); // NTSC_END - +#if 0 // NTSC_CLEANUP: Is this still needed?? if (SW_80STORE) g_uVideoMode &= ~VF_PAGE2; @@ -1364,7 +1364,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) g_bVideoUpdatedThisFrame = true; } } - +#endif // NTSC_CLEANUP return MemReadFloatingBus(uExecutedCycles); } From 95b6fde639e1a54c555eb8f69db19b1e998f4291 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 18:00:31 -0800 Subject: [PATCH 033/121] Cleanup & Optimize: g_nTextFlashCounter --- source/NTSC.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 6c8a05c1..0b1f77b7 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -144,7 +144,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void (*g_pFunc_ntscColorPixel)(int) = 0; //ntscColorSinglePixel; - static unsigned g_nTextFlashCounter = 0; + static uint8_t g_nTextFlashCounter = 0; static uint16_t g_nTextFlashMask = 0; static unsigned g_aPixelMaskGR [ 16]; @@ -463,11 +463,8 @@ inline void updateVideoHorzEOL() if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { g_nVideoClockVert = 0; - if (++g_nTextFlashCounter == 16) - { - g_nTextFlashCounter = 0; + if ((++g_nTextFlashCounter & 0xF) == 0) g_nTextFlashMask ^= -1; // 16-bits - } } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) @@ -1496,11 +1493,9 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { g_nVideoClockVert = 0; - if (++g_nTextFlashCounter == 16) - { - g_nTextFlashCounter = 0; + if ((++g_nTextFlashCounter & 0xF) == 0) g_nTextFlashMask ^= -1; // 16-bits - } + bRedraw = true; } From 8f2a3a217c6c26795e21e6a965ef3ef5ae907c37 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 18:03:44 -0800 Subject: [PATCH 034/121] Cleanup: updateVideoScannerAddress --- source/NTSC.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 0b1f77b7..5a7f0700 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -663,6 +663,14 @@ g_nLastColumnPixelNTSC=bt & 1 ; bt >>= 1; // 0000 0000 0000 00ab } } +inline void updateVideoScannerAddress() +{ + g_pVideoAddress = g_pScanLines[2*g_nVideoClockVert]; + g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; + g_nLastColumnPixelNTSC = 0; + g_nSignalBitsNTSC = 0; +} + //=========================================================================== static void init_video_tables (void) { @@ -1502,11 +1510,7 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFunc_NTSCVideoUpdateGraphics; - - g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; - g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; - g_nLastColumnPixelNTSC = 0; - g_nSignalBitsNTSC = 0; + updateVideoScannerAddress(); } } } From 1c2800080128d239905016b4fc555ceb8b5e688d Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 18:38:45 -0800 Subject: [PATCH 035/121] Clean up clock offsets and add note about potential bug --- source/NTSC.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 5a7f0700..42abbe6b 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -223,7 +223,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, - 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x380 + 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, + + 0x380 }; static unsigned APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = @@ -276,7 +278,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = { - {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x106F, + {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x106F, // bug? 0x106F 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, @@ -665,7 +667,7 @@ g_nLastColumnPixelNTSC=bt & 1 ; bt >>= 1; // 0000 0000 0000 00ab inline void updateVideoScannerAddress() { - g_pVideoAddress = g_pScanLines[2*g_nVideoClockVert]; + g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; From b6b384bc10fe646e61b44db8dee7383fbf3f4d77 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 18:51:52 -0800 Subject: [PATCH 036/121] Now displays Rainbow from Bug #254 correctly! --- source/NTSC.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 42abbe6b..1544247e 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -449,16 +449,20 @@ inline void updateVideoHorzEOL() if (g_nColorBurstPixels < 2) { g_pFunc_ntscMonoPixel(g_nLastColumnPixelNTSC); +#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer g_pFunc_ntscMonoPixel(0); g_pFunc_ntscMonoPixel(0); g_pFunc_ntscMonoPixel(0); +#endif } else { g_pFunc_ntscColorPixel(g_nLastColumnPixelNTSC); +#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer g_pFunc_ntscColorPixel(0); g_pFunc_ntscColorPixel(0); g_pFunc_ntscColorPixel(0); +#endif } } @@ -1500,6 +1504,10 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) { g_nVideoClockHorz = 0; + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFunc_NTSCVideoUpdateGraphics; + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { g_nVideoClockVert = 0; @@ -1510,10 +1518,7 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFunc_NTSCVideoUpdateGraphics; updateVideoScannerAddress(); - } } } From bddf3df22e2631a10e2c3020ca8820fec2c02a94 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 19:08:30 -0800 Subject: [PATCH 037/121] Fix minor Horz timing bug in updateVideoHorzEOL --- source/NTSC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1544247e..433d9169 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -442,7 +442,6 @@ inline void updateVideoHorzEOL() { if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) { - g_nVideoClockHorz = 0; if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { //VIDEO_DRAW_ENDLINE(); @@ -466,6 +465,8 @@ inline void updateVideoHorzEOL() } } + g_nVideoClockHorz = 0; + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { g_nVideoClockVert = 0; From 0786f759a8d2fd1ce8ef6c3bb81252530327a51b Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 19:14:18 -0800 Subject: [PATCH 038/121] Cleanup: g_aNTSC_Lines -> g_pScanlines, factor out updateVideoScannerAddress() --- source/NTSC.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 433d9169..e11da632 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //LPBYTE MemGetBankPtr(const UINT nBank); // Defines + #define HGR_TEST_PATTERN 0 #define PI 3.1415926535898f #define RAD_45 PI*0.25f #define RAD_90 PI*0.5f @@ -61,7 +62,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #endif #endif - #define HGR_TEST_PATTERN 0 // Types @@ -130,8 +130,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ]; - bgra_t *g_pVideoAddress; - bgra_t *g_aNTSC_Lines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + bgra_t *g_pVideoAddress = 0; + bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; typedef void (*Func_t)(long); @@ -390,6 +390,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA void init_chroma_phase_table(); void updateColorPhase(); void updateVideoHorzEOL(); + inline void updateVideoScannerAddress(); static void NTSC_UpdateVideoDoubleHires40(long cycles6502); static void NTSC_UpdateVideoDoubleHires80(long cycles6502); @@ -476,10 +477,7 @@ inline void updateVideoHorzEOL() if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { - g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; - g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; - g_nLastColumnPixelNTSC = 0; - g_nSignalBitsNTSC = 0; + updateVideoScannerAddress(); } } } @@ -672,7 +670,7 @@ g_nLastColumnPixelNTSC=bt & 1 ; bt >>= 1; // 0000 0000 0000 00ab inline void updateVideoScannerAddress() { - g_pVideoAddress = g_aNTSC_Lines[2*g_nVideoClockVert]; + g_pVideoAddress = g_pScanLines[2*g_nVideoClockVert]; g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; @@ -1416,9 +1414,9 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit updateMonochromeColor( 0xFF, 0xFF, 0xFF ); for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) - g_aNTSC_Lines[y] = (bgra_t*)(g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80); + g_pScanLines[y] = (bgra_t*)(g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80); - g_pVideoAddress = g_aNTSC_Lines[0]; // wsLines + g_pVideoAddress = g_pScanLines[0]; g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; From e14b004795c362ec46c5d3f4d487d7549e6cd016 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 19:18:39 -0800 Subject: [PATCH 039/121] Cleanup: Add getScanlineThis0Address() for out-of-bounds array checking --- source/NTSC.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index e11da632..a1b61597 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -540,6 +540,11 @@ inline uint32_t* getScanlineNext1Address() return (uint32_t*) (g_pVideoAddress - 1*FRAMEBUFFER_W); } +inline uint32_t* getScanlineThis0Address() +{ + return (uint32_t*) g_pVideoAddress; +} + inline uint32_t* getScanlinePrev1Address() { return (uint32_t*) (g_pVideoAddress + 1*FRAMEBUFFER_W); @@ -559,7 +564,7 @@ uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ) { - /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine0Address = getScanlineThis0Address(); /* */ uint32_t *pLine1Address = getScanlineNext1Address(); const uint32_t color0 = getScanlineColor( signal, pTable ); const uint32_t color1 = ((color0 & 0x00fcfcfc) >> 2); // 25% Blend (original) @@ -572,7 +577,7 @@ inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTa inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ) { - /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine0Address = getScanlineThis0Address(); /* */ uint32_t *pLine1Address = getScanlineNext1Address(); const uint32_t color0 = getScanlineColor( signal, pTable ); @@ -583,7 +588,7 @@ inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTa inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ) { - /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine0Address = getScanlineThis0Address(); /* */ uint32_t *pLine1Address = getScanlinePrev1Address(); /* */ uint32_t *pLine2Address = getScanlinePrev2Address(); @@ -598,7 +603,7 @@ inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTa inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ) { - /* */ uint32_t *pLine0Address = (uint32_t*)g_pVideoAddress; + /* */ uint32_t *pLine0Address = getScanlineThis0Address(); /* */ uint32_t *pLine1Address = getScanlinePrev1Address(); const uint32_t *pLine2Address = getScanlinePrev2Address(); From 851985e84602f2878004b7df3b1d6abefe70422d Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 19:46:40 -0800 Subject: [PATCH 040/121] Cleanup: add func pointer types --- source/NTSC.cpp | 194 ++++++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 96 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index a1b61597..cf8af5f7 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -35,12 +35,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Defines #define HGR_TEST_PATTERN 0 + #define PI 3.1415926535898f + #define DEG_TO_RAD(x) (PI*(x)/180.f) // 2PI=360, PI=180,PI/2=90,PI/4=45 #define RAD_45 PI*0.25f #define RAD_90 PI*0.5f #define RAD_360 PI*2.f - #define DEG_TO_RAD(x) (PI*(x)/180.f) // 2PI=360, PI=180,PI/2=90,PI/4=45 #ifndef CHROMA_BLUR #define CHROMA_BLUR 1 // Default: 1; 1 = blur along ~8 pixels; 0 = sharper @@ -132,17 +133,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA bgra_t *g_pVideoAddress = 0; bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; - typedef void (*Func_t)(long); - static Func_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; - - static void (* g_pFunc_NTSCVideoUpdateText )(long) = 0; // NTSC_UpdateVideoText40; - void (* g_pFunc_NTSCVideoUpdateGraphics)(long) = 0; // NTSC_UpdateVideoText40; - - static void (*g_pFunc_ntscMonoPixel )(int) = 0; //ntscMonoSinglePixel ; - static void (*g_pFunc_ntscColorPixel)(int) = 0; //ntscColorSinglePixel; + typedef void (*UpdateScreenFunc_t)(long); + static UpdateScreenFunc_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; + static UpdateScreenFunc_t g_pFuncUpdateTextScreen = 0; // NTSC_UpdateVideoText40; + static UpdateScreenFunc_t g_pFuncUpdateGraphicsScreen = 0; // NTSC_UpdateVideoText40; + typedef void (*UpdatePixelFunc_t)(uint16_t); + static UpdatePixelFunc_t g_pFuncUpdateBnWPixel = 0; //ntscMonoSinglePixel ; + static UpdatePixelFunc_t g_pFuncUpdateHuePixel = 0; //ntscColorSinglePixel; static uint8_t g_nTextFlashCounter = 0; static uint16_t g_nTextFlashMask = 0; @@ -401,14 +402,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void NTSC_UpdateVideoText40 (long cycles6502); static void NTSC_UpdateVideoText80 (long cycles6502); - static void ntscMonoSinglePixel (int compositeSignal); - static void ntscMonoDoublePixel (int compositeSignal); - static void ntscColorSinglePixel (int compositeSignal); - static void ntscColorDoublePixel (int compositeSignal); - static void ntscMonoTVSinglePixel (int compositeSignal); - static void ntscMonoTVDoublePixel (int compositeSignal); - static void ntscColorTVSinglePixel(int compositeSignal); - static void ntscColorTVDoublePixel(int compositeSignal); + static void ntscMonoSinglePixel (uint16_t compositeSignal); + static void ntscMonoDoublePixel (uint16_t compositeSignal); + static void ntscColorSinglePixel (uint16_t compositeSignal); + static void ntscColorDoublePixel (uint16_t compositeSignal); + static void ntscMonoTVSinglePixel (uint16_t compositeSignal); + static void ntscMonoTVDoublePixel (uint16_t compositeSignal); + static void ntscColorTVSinglePixel(uint16_t compositeSignal); + static void ntscColorTVDoublePixel(uint16_t compositeSignal); static void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ); //=========================================================================== @@ -448,20 +449,20 @@ inline void updateVideoHorzEOL() //VIDEO_DRAW_ENDLINE(); if (g_nColorBurstPixels < 2) { - g_pFunc_ntscMonoPixel(g_nLastColumnPixelNTSC); + g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); #if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer - g_pFunc_ntscMonoPixel(0); - g_pFunc_ntscMonoPixel(0); - g_pFunc_ntscMonoPixel(0); + g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(0); #endif } else { - g_pFunc_ntscColorPixel(g_nLastColumnPixelNTSC); + g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); #if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer - g_pFunc_ntscColorPixel(0); - g_pFunc_ntscColorPixel(0); - g_pFunc_ntscColorPixel(0); + g_pFuncUpdateHuePixel(0); + g_pFuncUpdateHuePixel(0); + g_pFuncUpdateHuePixel(0); #endif } } @@ -625,51 +626,52 @@ void VIDEO_DRAW_BITS( uint16_t bt ) // VIDEO_DRAW_BITS if (g_nColorBurstPixels < 2) { /* #1 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; /* #2 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; /* #3 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; /* #4 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; /* #5 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; /* #6 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; /* #7 of 7 */ - g_pFunc_ntscMonoPixel(bt & 1); bt >>= 1; - g_pFunc_ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bt & 1); + g_nLastColumnPixelNTSC=bt& 1 ; bt >>= 1; } else { - /* #1 of 7 */ // abcd efgh ijkl mnop - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0abc defg hijk lmno - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 00ab cdef ghi jklmn + /* #1 of 7 */ // abcd efgh ijkl mnop + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0abc defg hijk lmno + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 00ab cdef ghi jklmn /* #2 of 7 */ - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 000a bcde fghi jklm - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 abcd efgh ijkl + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 000a bcde fghi jklm + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 abcd efgh ijkl /* #3 of 7 */ - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0abc defg hijk - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 00ab cdef ghij + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0abc defg hijk + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 00ab cdef ghij /* #4 of 7 */ - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 000a bcde fghi - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 abcd efgh + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 000a bcde fghi + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 abcd efgh /* #5 of 7 */ - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0abc defg - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 00ab cdef + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 0abc defg + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 00ab cdef /* #6 of 7 */ - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 000a bcde - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 abcd + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 000a bcde + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 0000 abcd /* #7 of 7 */ - g_pFunc_ntscColorPixel(bt & 1); bt >>= 1; // 0000 0000 0000 0abc - g_pFunc_ntscColorPixel(bt & 1); -g_nLastColumnPixelNTSC=bt & 1 ; bt >>= 1; // 0000 0000 0000 00ab + g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 0000 0abc + g_pFuncUpdateHuePixel(bt & 1); + g_nLastColumnPixelNTSC=bt& 1 ; bt >>= 1; // 0000 0000 0000 00ab } } @@ -904,53 +906,53 @@ static void init_chroma_phase_table (void) } //=========================================================================== -static void ntscColorTVSinglePixel (int compositeSignal) +static void ntscColorTVSinglePixel (uint16_t compositeSignal) { updateFramebufferColorTVSingleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscColorTVDoublePixel (int compositeSignal) +static void ntscColorTVDoublePixel (uint16_t compositeSignal) { updateFramebufferColorTVDoubleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscColorSinglePixel (int compositeSignal) +static void ntscColorSinglePixel (uint16_t compositeSignal) { updateFramebufferMonitorSingleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscColorDoublePixel (int compositeSignal) +static void ntscColorDoublePixel (uint16_t compositeSignal) { updateFramebufferMonitorDoubleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscMonoSinglePixel (int compositeSignal) +static void ntscMonoSinglePixel (uint16_t compositeSignal) { updateFramebufferMonitorSingleScanline(compositeSignal, g_aBnWMonitorCustom); } //=========================================================================== -static void ntscMonoDoublePixel (int compositeSignal) +static void ntscMonoDoublePixel (uint16_t compositeSignal) { updateFramebufferMonitorDoubleScanline(compositeSignal, g_aBnWMonitorCustom); } //=========================================================================== -static void ntscMonoTVSinglePixel (int compositeSignal) +static void ntscMonoTVSinglePixel (uint16_t compositeSignal) { updateFramebufferColorTVSingleScanline(compositeSignal, g_aBnWColorTVCustom); } //=========================================================================== -static void ntscMonoTVDoublePixel (int compositeSignal) +static void ntscMonoTVDoublePixel (uint16_t compositeSignal) { updateFramebufferColorTVDoubleScanline(compositeSignal, g_aBnWColorTVCustom); } @@ -976,9 +978,9 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) void NTSC_SetVideoTextMode( int cols ) { if( cols == 40 ) - g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; + g_pFuncUpdateTextScreen = NTSC_UpdateVideoText40; else - g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText80; + g_pFuncUpdateTextScreen = NTSC_UpdateVideoText80; } //=========================================================================== @@ -998,27 +1000,27 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) if (bVideoModeFlags & VF_TEXT) { if (bVideoModeFlags & VF_80COL) - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText80; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoText80; else - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoText40; } else if (bVideoModeFlags & VF_HIRES) { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleHires80; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleHires80; else - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleHires40; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleHires40; else - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoSingleHires40; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoSingleHires40; } else { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleLores80; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleLores80; else - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoDoubleLores40; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleLores40; else - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoSingleLores40; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoSingleLores40; } } @@ -1033,12 +1035,12 @@ void NTSC_SetVideoStyle() // (int v, int s) case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: if (half) { - g_pFunc_ntscMonoPixel = ntscMonoTVSinglePixel; - g_pFunc_ntscColorPixel = ntscColorTVSinglePixel; + g_pFuncUpdateBnWPixel = ntscMonoTVSinglePixel; + g_pFuncUpdateHuePixel = ntscColorTVSinglePixel; } else { - g_pFunc_ntscMonoPixel = ntscMonoTVDoublePixel; - g_pFunc_ntscColorPixel = ntscColorTVDoublePixel; + g_pFuncUpdateBnWPixel = ntscMonoTVDoublePixel; + g_pFuncUpdateHuePixel = ntscColorTVDoublePixel; } break; @@ -1046,12 +1048,12 @@ void NTSC_SetVideoStyle() // (int v, int s) default: if (half) { - g_pFunc_ntscMonoPixel = ntscMonoSinglePixel; - g_pFunc_ntscColorPixel = ntscColorSinglePixel; + g_pFuncUpdateBnWPixel = ntscMonoSinglePixel; + g_pFuncUpdateHuePixel = ntscColorSinglePixel; } else { - g_pFunc_ntscMonoPixel = ntscMonoDoublePixel; - g_pFunc_ntscColorPixel = ntscColorDoublePixel; + g_pFuncUpdateBnWPixel = ntscMonoDoublePixel; + g_pFuncUpdateHuePixel = ntscColorDoublePixel; } break; @@ -1062,10 +1064,10 @@ void NTSC_SetVideoStyle() // (int v, int s) updateMonochromeColor( r, g, b ); // Custom Monochrome color if (half) { - g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoTVSinglePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoTVSinglePixel; } else { - g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoTVDoublePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoTVDoublePixel; } break; @@ -1101,11 +1103,11 @@ _mono: updateMonochromeColor( r, g, b ); // Custom Monochrome color if (half) { - g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoSinglePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoSinglePixel; } else { - g_pFunc_ntscMonoPixel = g_pFunc_ntscColorPixel = ntscMonoDoublePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoDoublePixel; } break; } @@ -1118,7 +1120,7 @@ void NTSC_UpdateVideoDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pFunc_NTSCVideoUpdateText( cycles6502 ); + g_pFuncUpdateTextScreen( cycles6502 ); return; } @@ -1152,7 +1154,7 @@ void NTSC_UpdateVideoDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pFunc_NTSCVideoUpdateText( cycles6502 ); + g_pFuncUpdateTextScreen( cycles6502 ); return; } @@ -1191,7 +1193,7 @@ void NTSC_UpdateVideoDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pFunc_NTSCVideoUpdateText( cycles6502 ); + g_pFuncUpdateTextScreen( cycles6502 ); return; } @@ -1225,7 +1227,7 @@ void NTSC_UpdateVideoDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pFunc_NTSCVideoUpdateText( cycles6502 ); + g_pFuncUpdateTextScreen( cycles6502 ); return; } @@ -1268,7 +1270,7 @@ void NTSC_UpdateVideoSingleHires40 (long cycles6502) if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pFunc_NTSCVideoUpdateText( cycles6502 ); + g_pFuncUpdateTextScreen( cycles6502 ); return; } @@ -1303,7 +1305,7 @@ void NTSC_UpdateVideoSingleLores40 (long cycles6502) if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { - g_pFunc_NTSCVideoUpdateText( cycles6502 ); + g_pFuncUpdateTextScreen( cycles6502 ); return; } @@ -1423,8 +1425,8 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit g_pVideoAddress = g_pScanLines[0]; - g_pFunc_NTSCVideoUpdateText = NTSC_UpdateVideoText40; - g_pFunc_NTSCVideoUpdateGraphics = NTSC_UpdateVideoText40; + g_pFuncUpdateTextScreen = NTSC_UpdateVideoText40; + g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoText40; VideoReinitialize(); // Setup g_pFunc_ntsc*Pixel() @@ -1497,7 +1499,7 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) bool bRedraw = cycles6502 >= VIDEO_SCANNER_6502_CYCLES; // if( g_bFullSpeed ) -// g_pFunc_NTSCVideoUpdateGraphics( cycles6502 ); +// g_pFuncUpdateGraphicsScreen( cycles6502 ); // else while( cycles6502 > VIDEO_SCANNER_6502_CYCLES ) @@ -1510,7 +1512,7 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) g_nVideoClockHorz = 0; if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFunc_NTSCVideoUpdateGraphics; + g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFuncUpdateGraphicsScreen; if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { @@ -1532,6 +1534,6 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) g_apFuncVideoUpdateScanline[ y ]( VIDEO_SCANNER_MAX_HORZ ); int nCyclesVBlank = (VIDEO_SCANNER_MAX_VERT - VIDEO_SCANNER_Y_DISPLAY) * VIDEO_SCANNER_MAX_HORZ; - g_pFunc_NTSCVideoUpdateGraphics( nCyclesVBlank ); + g_pFuncUpdateGraphicsScreen( nCyclesVBlank ); } } From fb19d883eb8728ac5763fe6ea07e27de10fd5bb9 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 20:00:24 -0800 Subject: [PATCH 041/121] cleanup updateScreen*() --- source/NTSC.cpp | 104 ++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index cf8af5f7..1cb55f95 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -138,8 +138,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA typedef void (*UpdateScreenFunc_t)(long); static UpdateScreenFunc_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; - static UpdateScreenFunc_t g_pFuncUpdateTextScreen = 0; // NTSC_UpdateVideoText40; - static UpdateScreenFunc_t g_pFuncUpdateGraphicsScreen = 0; // NTSC_UpdateVideoText40; + static UpdateScreenFunc_t g_pFuncUpdateTextScreen = 0; // updateScreenText40; + static UpdateScreenFunc_t g_pFuncUpdateGraphicsScreen = 0; // updateScreenText40; typedef void (*UpdatePixelFunc_t)(uint16_t); static UpdatePixelFunc_t g_pFuncUpdateBnWPixel = 0; //ntscMonoSinglePixel ; @@ -388,20 +388,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // prototypes from Memory.h //unsigned char * MemGetAuxPtr (unsigned short); //unsigned char * MemGetMainPtr (unsigned short); - void init_chroma_phase_table(); - void updateColorPhase(); - void updateVideoHorzEOL(); - inline void updateVideoScannerAddress(); + inline float clampZeroOne( const float & x ); + inline uint8_t getCharSetBits( const int iChar ); + inline uint16_t getLoResBits( uint8_t iByte ); + inline uint32_t* getScanlineNext1Address(); + inline uint32_t* getScanlineThis0Address(); + inline uint32_t* getScanlinePrev1Address(); + inline uint32_t* getScanlinePrev2Address(); + inline void updateColorPhase(); + inline void updateVideoScannerHorzEOL(); + inline void updateVideoScannerAddress(); - static void NTSC_UpdateVideoDoubleHires40(long cycles6502); - static void NTSC_UpdateVideoDoubleHires80(long cycles6502); - static void NTSC_UpdateVideoDoubleLores40(long cycles6502); - static void NTSC_UpdateVideoDoubleLores80(long cycles6502); - static void NTSC_UpdateVideoSingleHires40(long cycles6502); - static void NTSC_UpdateVideoSingleLores40(long cycles6502); - static void NTSC_UpdateVideoText40 (long cycles6502); - static void NTSC_UpdateVideoText80 (long cycles6502); + static void init_chroma_phase_table(); + static void updateScreenDoubleHires40(long cycles6502); + static void updateScreenDoubleHires80(long cycles6502); + static void updateScreenDoubleLores40(long cycles6502); + static void updateScreenDoubleLores80(long cycles6502); + static void updateScreenSingleHires40(long cycles6502); + static void updateScreenSingleLores40(long cycles6502); + static void updateScreenText40 (long cycles6502); + static void updateScreenText80 (long cycles6502); + + static void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b ); static void ntscMonoSinglePixel (uint16_t compositeSignal); static void ntscMonoDoublePixel (uint16_t compositeSignal); static void ntscColorSinglePixel (uint16_t compositeSignal); @@ -410,7 +419,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void ntscMonoTVDoublePixel (uint16_t compositeSignal); static void ntscColorTVSinglePixel(uint16_t compositeSignal); static void ntscColorTVDoublePixel(uint16_t compositeSignal); - static void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ); //=========================================================================== inline float clampZeroOne( const float & x ) @@ -440,7 +448,7 @@ inline void updateColorPhase() } //=========================================================================== -inline void updateVideoHorzEOL() +inline void updateVideoScannerHorzEOL() { if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) { @@ -958,7 +966,7 @@ static void ntscMonoTVDoublePixel (uint16_t compositeSignal) } //=========================================================================== -void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) +void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b ) { for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ ) { @@ -978,9 +986,9 @@ void updateMonochromeColor( uint16_t r, uint16_t g, uint16_t b ) void NTSC_SetVideoTextMode( int cols ) { if( cols == 40 ) - g_pFuncUpdateTextScreen = NTSC_UpdateVideoText40; + g_pFuncUpdateTextScreen = updateScreenText40; else - g_pFuncUpdateTextScreen = NTSC_UpdateVideoText80; + g_pFuncUpdateTextScreen = updateScreenText80; } //=========================================================================== @@ -1000,27 +1008,27 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) if (bVideoModeFlags & VF_TEXT) { if (bVideoModeFlags & VF_80COL) - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoText80; + g_pFuncUpdateGraphicsScreen = updateScreenText80; else - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoText40; + g_pFuncUpdateGraphicsScreen = updateScreenText40; } else if (bVideoModeFlags & VF_HIRES) { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleHires80; + g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80; else - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleHires40; + g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires40; else - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoSingleHires40; + g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40; } else { if (bVideoModeFlags & VF_DHIRES) if (bVideoModeFlags & VF_80COL) - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleLores80; + g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80; else - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoDoubleLores40; + g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores40; else - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoSingleLores40; + g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40; } } @@ -1061,7 +1069,7 @@ void NTSC_SetVideoStyle() // (int v, int s) r = 0xFF; g = 0xFF; b = 0xFF; - updateMonochromeColor( r, g, b ); // Custom Monochrome color + updateMonochromeTables( r, g, b ); // Custom Monochrome color if (half) { g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoTVSinglePixel; @@ -1100,7 +1108,7 @@ void NTSC_SetVideoStyle() // (int v, int s) g = (g_nMonochromeRGB >> 8) & 0xFF; b = (g_nMonochromeRGB >> 16) & 0xFF; _mono: - updateMonochromeColor( r, g, b ); // Custom Monochrome color + updateMonochromeTables( r, g, b ); // Custom Monochrome color if (half) { g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoSinglePixel; @@ -1114,7 +1122,7 @@ _mono: } //=========================================================================== -void NTSC_UpdateVideoDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 +void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 { unsigned ad; @@ -1142,12 +1150,12 @@ void NTSC_UpdateVideoDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 VIDEO_DRAW_BITS( bits ); } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires +void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires { unsigned ad; uint16_t bits; @@ -1182,12 +1190,12 @@ void NTSC_UpdateVideoDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires g_nLastColumnPixelNTSC = (bits >> 14) & 3; } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores +void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores { unsigned ad; @@ -1216,12 +1224,12 @@ void NTSC_UpdateVideoDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores VIDEO_DRAW_BITS( bits ); } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores +void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores { unsigned ad; @@ -1259,12 +1267,12 @@ void NTSC_UpdateVideoDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores g_nLastColumnPixelNTSC = (bits >> 14) & 3; } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoSingleHires40 (long cycles6502) +void updateScreenSingleHires40 (long cycles6502) { unsigned ad; @@ -1294,12 +1302,12 @@ void NTSC_UpdateVideoSingleHires40 (long cycles6502) VIDEO_DRAW_BITS( bits ); } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoSingleLores40 (long cycles6502) +void updateScreenSingleLores40 (long cycles6502) { unsigned ad; @@ -1328,12 +1336,12 @@ void NTSC_UpdateVideoSingleLores40 (long cycles6502) VIDEO_DRAW_BITS( bits ); } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoText40 (long cycles6502) +void updateScreenText40 (long cycles6502) { unsigned ad; @@ -1359,12 +1367,12 @@ void NTSC_UpdateVideoText40 (long cycles6502) VIDEO_DRAW_BITS( bits ); } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } //=========================================================================== -void NTSC_UpdateVideoText80 (long cycles6502) +void updateScreenText80 (long cycles6502) { unsigned int ad; @@ -1400,7 +1408,7 @@ void NTSC_UpdateVideoText80 (long cycles6502) VIDEO_DRAW_BITS( bits ); } } - updateVideoHorzEOL(); + updateVideoScannerHorzEOL(); } } @@ -1418,15 +1426,15 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit make_csbits(); init_video_tables(); init_chroma_phase_table(); - updateMonochromeColor( 0xFF, 0xFF, 0xFF ); + updateMonochromeTables( 0xFF, 0xFF, 0xFF ); for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) g_pScanLines[y] = (bgra_t*)(g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80); g_pVideoAddress = g_pScanLines[0]; - g_pFuncUpdateTextScreen = NTSC_UpdateVideoText40; - g_pFuncUpdateGraphicsScreen = NTSC_UpdateVideoText40; + g_pFuncUpdateTextScreen = updateScreenText40; + g_pFuncUpdateGraphicsScreen = updateScreenText40; VideoReinitialize(); // Setup g_pFunc_ntsc*Pixel() From 2845ec65ee3f1aee7008425b1c24d4e1fc41345f Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 20:03:57 -0800 Subject: [PATCH 042/121] Cleanup: VIDEO_DRAW_BITS -> updatePixels --- source/NTSC.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1cb55f95..0ad9ef85 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -391,11 +391,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA inline float clampZeroOne( const float & x ); inline uint8_t getCharSetBits( const int iChar ); inline uint16_t getLoResBits( uint8_t iByte ); + inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ); inline uint32_t* getScanlineNext1Address(); inline uint32_t* getScanlineThis0Address(); inline uint32_t* getScanlinePrev1Address(); inline uint32_t* getScanlinePrev2Address(); inline void updateColorPhase(); + inline void updatePixels( uint16_t bits ); inline void updateVideoScannerHorzEOL(); inline void updateVideoScannerAddress(); @@ -565,7 +567,7 @@ inline uint32_t* getScanlinePrev2Address() } -uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) +inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) { g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 14-bit return *(uint32_t*) &pTable[ g_nSignalBitsNTSC ]; @@ -628,8 +630,7 @@ inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTa #endif //=========================================================================== -inline -void VIDEO_DRAW_BITS( uint16_t bt ) // VIDEO_DRAW_BITS +inline void updatePixels( uint16_t bt ) { if (g_nColorBurstPixels < 2) { @@ -1147,7 +1148,7 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); } } updateVideoScannerHorzEOL(); @@ -1186,7 +1187,7 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires bits = ((m & 0x7f) << 7) | (a & 0x7f); bits = (bits << 1) | g_nLastColumnPixelNTSC; - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); g_nLastColumnPixelNTSC = (bits >> 14) & 3; } } @@ -1221,7 +1222,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores uint8_t m = pMain[0]; uint16_t lo = getLoResBits( m ); uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); } } updateVideoScannerHorzEOL(); @@ -1263,7 +1264,7 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores uint16_t main = lo >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); uint16_t bits = (main << 7) | (aux & 0x7f); - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); g_nLastColumnPixelNTSC = (bits >> 14) & 3; } } @@ -1299,7 +1300,7 @@ void updateScreenSingleHires40 (long cycles6502) uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 if (m & 0x80) bits = (bits << 1) | g_nLastColumnPixelNTSC; - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); } } updateVideoScannerHorzEOL(); @@ -1333,7 +1334,7 @@ void updateScreenSingleLores40 (long cycles6502) uint8_t m = pMain[0]; uint16_t lo = getLoResBits( m ); uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2); - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); } } updateVideoScannerHorzEOL(); @@ -1364,7 +1365,7 @@ void updateScreenText40 (long cycles6502) uint16_t bits = g_aPixelDoubleMaskHGR[c & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) bits ^= g_nTextFlashMask; - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); } } updateVideoScannerHorzEOL(); @@ -1405,7 +1406,7 @@ void updateScreenText80 (long cycles6502) aux ^= g_nTextFlashMask; uint16_t bits = (main << 7) | aux; - VIDEO_DRAW_BITS( bits ); + updatePixels( bits ); } } updateVideoScannerHorzEOL(); From bf815f1b6c249edf02a29f9a2515579362aac67f Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 20:05:49 -0800 Subject: [PATCH 043/121] Cleanup: updatePixels() argument: bt -> bits --- source/NTSC.cpp | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 0ad9ef85..1626a08f 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -630,57 +630,57 @@ inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTa #endif //=========================================================================== -inline void updatePixels( uint16_t bt ) +inline void updatePixels( uint16_t bits ) { if (g_nColorBurstPixels < 2) { /* #1 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; /* #2 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; /* #3 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; /* #4 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; /* #5 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; /* #6 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; /* #7 of 7 */ - g_pFuncUpdateBnWPixel(bt & 1); bt >>= 1; - g_pFuncUpdateBnWPixel(bt & 1); - g_nLastColumnPixelNTSC=bt& 1 ; bt >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; + g_pFuncUpdateBnWPixel(bits & 1); + g_nLastColumnPixelNTSC=bits& 1 ; bits >>= 1; } else { - /* #1 of 7 */ // abcd efgh ijkl mnop - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0abc defg hijk lmno - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 00ab cdef ghi jklmn + /* #1 of 7 */ // abcd efgh ijkl mnop + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0abc defg hijk lmno + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 00ab cdef ghi jklmn /* #2 of 7 */ - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 000a bcde fghi jklm - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 abcd efgh ijkl + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 000a bcde fghi jklm + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 abcd efgh ijkl /* #3 of 7 */ - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0abc defg hijk - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 00ab cdef ghij + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0abc defg hijk + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 00ab cdef ghij /* #4 of 7 */ - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 000a bcde fghi - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 abcd efgh + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 000a bcde fghi + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 abcd efgh /* #5 of 7 */ - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 0abc defg - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 00ab cdef + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0abc defg + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 00ab cdef /* #6 of 7 */ - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 000a bcde - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 0000 abcd + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 000a bcde + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0000 abcd /* #7 of 7 */ - g_pFuncUpdateHuePixel(bt & 1); bt >>= 1; // 0000 0000 0000 0abc - g_pFuncUpdateHuePixel(bt & 1); - g_nLastColumnPixelNTSC=bt& 1 ; bt >>= 1; // 0000 0000 0000 00ab + g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0000 0abc + g_pFuncUpdateHuePixel(bits & 1); + g_nLastColumnPixelNTSC=bits& 1 ; bits >>= 1; // 0000 0000 0000 00ab } } From 83e5de9e74aa5e1c63996550c24168bcc944f373 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 20:20:30 -0800 Subject: [PATCH 044/121] Massive cleanup: consisten updatePixel*() updateScreen*() func names --- source/NTSC.cpp | 83 +++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1626a08f..1fb57439 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -142,8 +142,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static UpdateScreenFunc_t g_pFuncUpdateGraphicsScreen = 0; // updateScreenText40; typedef void (*UpdatePixelFunc_t)(uint16_t); - static UpdatePixelFunc_t g_pFuncUpdateBnWPixel = 0; //ntscMonoSinglePixel ; - static UpdatePixelFunc_t g_pFuncUpdateHuePixel = 0; //ntscColorSinglePixel; + static UpdatePixelFunc_t g_pFuncUpdateBnWPixel = 0; //updatePixelBnWMonitorSingleScanline; + static UpdatePixelFunc_t g_pFuncUpdateHuePixel = 0; //updatePixelHueMonitorSingleScanline; static uint8_t g_nTextFlashCounter = 0; static uint16_t g_nTextFlashMask = 0; @@ -402,25 +402,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA inline void updateVideoScannerAddress(); static void init_chroma_phase_table(); - - static void updateScreenDoubleHires40(long cycles6502); - static void updateScreenDoubleHires80(long cycles6502); - static void updateScreenDoubleLores40(long cycles6502); - static void updateScreenDoubleLores80(long cycles6502); - static void updateScreenSingleHires40(long cycles6502); - static void updateScreenSingleLores40(long cycles6502); - static void updateScreenText40 (long cycles6502); - static void updateScreenText80 (long cycles6502); - static void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b ); - static void ntscMonoSinglePixel (uint16_t compositeSignal); - static void ntscMonoDoublePixel (uint16_t compositeSignal); - static void ntscColorSinglePixel (uint16_t compositeSignal); - static void ntscColorDoublePixel (uint16_t compositeSignal); - static void ntscMonoTVSinglePixel (uint16_t compositeSignal); - static void ntscMonoTVDoublePixel (uint16_t compositeSignal); - static void ntscColorTVSinglePixel(uint16_t compositeSignal); - static void ntscColorTVDoublePixel(uint16_t compositeSignal); + + static void updatePixelBnWColorTVSingleScanline( uint16_t compositeSignal ); + static void updatePixelBnWColorTVDoubleScanline( uint16_t compositeSignal ); + static void updatePixelBnWMonitorSingleScanline( uint16_t compositeSignal ); + static void updatePixelBnWMonitorDoubleScanline( uint16_t compositeSignal ); + static void updatePixelHueColorTVSingleScanline( uint16_t compositeSignal ); + static void updatePixelHueColorTVDoubleScanline( uint16_t compositeSignal ); + static void updatePixelHueMonitorSingleScanline( uint16_t compositeSignal ); + static void updatePixelHueMonitorDoubleScanline( uint16_t compositeSignal ); + + static void updateScreenDoubleHires40( long cycles6502 ); + static void updateScreenDoubleHires80( long cycles6502 ); + static void updateScreenDoubleLores40( long cycles6502 ); + static void updateScreenDoubleLores80( long cycles6502 ); + static void updateScreenSingleHires40( long cycles6502 ); + static void updateScreenSingleLores40( long cycles6502 ); + static void updateScreenText40 ( long cycles6502 ); + static void updateScreenText80 ( long cycles6502 ); + //=========================================================================== inline float clampZeroOne( const float & x ) @@ -697,7 +698,7 @@ static void init_video_tables (void) { /* Convert 7-bit monochrome luminance to 14-bit double pixel luminance - Chroma will be applied later based on the color phase in ntscColorDoublePixel( luminanceBit ) + Chroma will be applied later based on the color phase in updatePixelHueMonitorDoubleScanline( luminanceBit ) 0x001 -> 0x0003 0x002 -> 0x000C 0x004 -> 0x0030 @@ -915,53 +916,53 @@ static void init_chroma_phase_table (void) } //=========================================================================== -static void ntscColorTVSinglePixel (uint16_t compositeSignal) +static void updatePixelHueColorTVSingleScanline (uint16_t compositeSignal) { updateFramebufferColorTVSingleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscColorTVDoublePixel (uint16_t compositeSignal) +static void updatePixelHueColorTVDoubleScanline (uint16_t compositeSignal) { updateFramebufferColorTVDoubleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscColorSinglePixel (uint16_t compositeSignal) +static void updatePixelHueMonitorSingleScanline (uint16_t compositeSignal) { updateFramebufferMonitorSingleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscColorDoublePixel (uint16_t compositeSignal) +static void updatePixelHueMonitorDoubleScanline (uint16_t compositeSignal) { updateFramebufferMonitorDoubleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); updateColorPhase(); } //=========================================================================== -static void ntscMonoSinglePixel (uint16_t compositeSignal) +static void updatePixelBnWMonitorSingleScanline (uint16_t compositeSignal) { updateFramebufferMonitorSingleScanline(compositeSignal, g_aBnWMonitorCustom); } //=========================================================================== -static void ntscMonoDoublePixel (uint16_t compositeSignal) +static void updatePixelBnWMonitorDoubleScanline (uint16_t compositeSignal) { updateFramebufferMonitorDoubleScanline(compositeSignal, g_aBnWMonitorCustom); } //=========================================================================== -static void ntscMonoTVSinglePixel (uint16_t compositeSignal) +static void updatePixelBnWColorTVSingleScanline (uint16_t compositeSignal) { updateFramebufferColorTVSingleScanline(compositeSignal, g_aBnWColorTVCustom); } //=========================================================================== -static void ntscMonoTVDoublePixel (uint16_t compositeSignal) +static void updatePixelBnWColorTVDoubleScanline (uint16_t compositeSignal) { updateFramebufferColorTVDoubleScanline(compositeSignal, g_aBnWColorTVCustom); } @@ -1044,12 +1045,12 @@ void NTSC_SetVideoStyle() // (int v, int s) case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: if (half) { - g_pFuncUpdateBnWPixel = ntscMonoTVSinglePixel; - g_pFuncUpdateHuePixel = ntscColorTVSinglePixel; + g_pFuncUpdateBnWPixel = updatePixelBnWColorTVSingleScanline; + g_pFuncUpdateHuePixel = updatePixelHueColorTVSingleScanline; } else { - g_pFuncUpdateBnWPixel = ntscMonoTVDoublePixel; - g_pFuncUpdateHuePixel = ntscColorTVDoublePixel; + g_pFuncUpdateBnWPixel = updatePixelBnWColorTVDoubleScanline; + g_pFuncUpdateHuePixel = updatePixelHueColorTVDoubleScanline; } break; @@ -1057,12 +1058,12 @@ void NTSC_SetVideoStyle() // (int v, int s) default: if (half) { - g_pFuncUpdateBnWPixel = ntscMonoSinglePixel; - g_pFuncUpdateHuePixel = ntscColorSinglePixel; + g_pFuncUpdateBnWPixel = updatePixelBnWMonitorSingleScanline; + g_pFuncUpdateHuePixel = updatePixelHueMonitorSingleScanline; } else { - g_pFuncUpdateBnWPixel = ntscMonoDoublePixel; - g_pFuncUpdateHuePixel = ntscColorDoublePixel; + g_pFuncUpdateBnWPixel = updatePixelBnWMonitorDoubleScanline; + g_pFuncUpdateHuePixel = updatePixelHueMonitorDoubleScanline; } break; @@ -1073,10 +1074,10 @@ void NTSC_SetVideoStyle() // (int v, int s) updateMonochromeTables( r, g, b ); // Custom Monochrome color if (half) { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoTVSinglePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVSingleScanline; } else { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoTVDoublePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVDoubleScanline; } break; @@ -1112,11 +1113,11 @@ _mono: updateMonochromeTables( r, g, b ); // Custom Monochrome color if (half) { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoSinglePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorSingleScanline; } else { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = ntscMonoDoublePixel; + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorDoubleScanline; } break; } From d5abdcc97cde84a19255c5e171b2cbe93d652ec9 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 20:58:27 -0800 Subject: [PATCH 045/121] Massive alphabetize cleanup --- source/NTSC.cpp | 722 +++++++++++++++++++++++++----------------------- source/NTSC.h | 5 +- 2 files changed, 373 insertions(+), 354 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1fb57439..f058a3dd 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -42,6 +42,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define RAD_90 PI*0.5f #define RAD_360 PI*2.f + // sadly float64 precision is needed + #define real double #ifndef CHROMA_BLUR #define CHROMA_BLUR 1 // Default: 1; 1 = blur along ~8 pixels; 0 = sharper @@ -56,7 +58,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define CYCLESTART (DEG_TO_RAD(45)) #else // sharpness is higher, less color bleed #if CHROMA_FILTER == 2 - #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = init_signal_prefilter(z); + #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = initFilterSignal(z); #else // #define CYCLESTART DEG_TO_RAD(90) // (PI*0.5) // PI/2 = 90 degrees // HGR: Great, GR: fail on brown #define CYCLESTART DEG_TO_RAD(115.f) // GR perfect match of slow method @@ -393,15 +395,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA inline uint16_t getLoResBits( uint8_t iByte ); inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ); inline uint32_t* getScanlineNext1Address(); - inline uint32_t* getScanlineThis0Address(); inline uint32_t* getScanlinePrev1Address(); inline uint32_t* getScanlinePrev2Address(); + inline uint32_t* getScanlineThis0Address(); inline void updateColorPhase(); + inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ); + inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ); + inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ); + inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ); inline void updatePixels( uint16_t bits ); inline void updateVideoScannerHorzEOL(); inline void updateVideoScannerAddress(); - static void init_chroma_phase_table(); + static void initChromaPhaseTables(); + static real initFilterChroma (real z); + static real initFilterLuma0 (real z); + static real initFilterLuma1 (real z); + static real initFilterSignal(real z); + static void initPixelDoubleMasks(void); static void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b ); static void updatePixelBnWColorTVSingleScanline( uint16_t compositeSignal ); @@ -443,6 +454,38 @@ inline uint16_t getLoResBits( uint8_t iByte ) return g_aPixelMaskGR[ (iByte >> (g_nVideoClockVert & 4)) & 0xF ]; } +//=========================================================================== +inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) +{ + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 14-bit + return *(uint32_t*) &pTable[ g_nSignalBitsNTSC ]; +} + +//=========================================================================== +inline uint32_t* getScanlineNext1Address() +{ + return (uint32_t*) (g_pVideoAddress - 1*FRAMEBUFFER_W); +} + +//=========================================================================== +inline uint32_t* getScanlinePrev1Address() +{ + return (uint32_t*) (g_pVideoAddress + 1*FRAMEBUFFER_W); +} + +//=========================================================================== +inline uint32_t* getScanlinePrev2Address() +{ + return (uint32_t*) (g_pVideoAddress + 2*FRAMEBUFFER_W); + +} + +//=========================================================================== +inline uint32_t* getScanlineThis0Address() +{ + return (uint32_t*) g_pVideoAddress; +} + //=========================================================================== inline void updateColorPhase() { @@ -450,50 +493,6 @@ inline void updateColorPhase() g_nColorPhaseNTSC &= 3; } -//=========================================================================== -inline void updateVideoScannerHorzEOL() -{ - if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) - { - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - //VIDEO_DRAW_ENDLINE(); - if (g_nColorBurstPixels < 2) - { - g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); -#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer - g_pFuncUpdateBnWPixel(0); - g_pFuncUpdateBnWPixel(0); - g_pFuncUpdateBnWPixel(0); -#endif - } - else - { - g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); -#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer - g_pFuncUpdateHuePixel(0); - g_pFuncUpdateHuePixel(0); - g_pFuncUpdateHuePixel(0); -#endif - } - } - - g_nVideoClockHorz = 0; - - if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) - { - g_nVideoClockVert = 0; - if ((++g_nTextFlashCounter & 0xF) == 0) - g_nTextFlashMask ^= -1; // 16-bits - } - - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) - { - updateVideoScannerAddress(); - } - } -} - #if 0 #define updateFramebufferMonitorSingleScanline(signal,table) \ do { \ @@ -547,57 +546,7 @@ inline void updateVideoScannerHorzEOL() } while(0) #else -inline uint32_t* getScanlineNext1Address() -{ - return (uint32_t*) (g_pVideoAddress - 1*FRAMEBUFFER_W); -} - -inline uint32_t* getScanlineThis0Address() -{ - return (uint32_t*) g_pVideoAddress; -} - -inline uint32_t* getScanlinePrev1Address() -{ - return (uint32_t*) (g_pVideoAddress + 1*FRAMEBUFFER_W); -} - -inline uint32_t* getScanlinePrev2Address() -{ - return (uint32_t*) (g_pVideoAddress + 2*FRAMEBUFFER_W); - -} - -inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) -{ - g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 14-bit - return *(uint32_t*) &pTable[ g_nSignalBitsNTSC ]; -} - -inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ) -{ - /* */ uint32_t *pLine0Address = getScanlineThis0Address(); - /* */ uint32_t *pLine1Address = getScanlineNext1Address(); - const uint32_t color0 = getScanlineColor( signal, pTable ); - const uint32_t color1 = ((color0 & 0x00fcfcfc) >> 2); // 25% Blend (original) -// const uint32_t color1 = ((color0 & 0x00fefefe) >> 1); // 50% Blend -- looks OK most of the time; Archon looks poor - - /* */ *pLine1Address = color1 | ALPHA32_MASK; - /* */ *pLine0Address = color0; - /* */ g_pVideoAddress++; -} - -inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ) -{ - /* */ uint32_t *pLine0Address = getScanlineThis0Address(); - /* */ uint32_t *pLine1Address = getScanlineNext1Address(); - const uint32_t color0 = getScanlineColor( signal, pTable ); - - /* */ *pLine1Address = color0; - /* */ *pLine0Address = color0; - /* */ g_pVideoAddress++; -} - +//=========================================================================== inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ) { /* */ uint32_t *pLine0Address = getScanlineThis0Address(); @@ -613,6 +562,7 @@ inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTa /* */ g_pVideoAddress++; } +//=========================================================================== inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ) { /* */ uint32_t *pLine0Address = getScanlineThis0Address(); @@ -628,6 +578,31 @@ inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTa /* */ g_pVideoAddress++; } +//=========================================================================== +inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ) +{ + /* */ uint32_t *pLine0Address = getScanlineThis0Address(); + /* */ uint32_t *pLine1Address = getScanlineNext1Address(); + const uint32_t color0 = getScanlineColor( signal, pTable ); + const uint32_t color1 = ((color0 & 0x00fcfcfc) >> 2); // 25% Blend (original) +// const uint32_t color1 = ((color0 & 0x00fefefe) >> 1); // 50% Blend -- looks OK most of the time; Archon looks poor + + /* */ *pLine1Address = color1 | ALPHA32_MASK; + /* */ *pLine0Address = color0; + /* */ g_pVideoAddress++; +} + +//=========================================================================== +inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ) +{ + /* */ uint32_t *pLine0Address = getScanlineThis0Address(); + /* */ uint32_t *pLine1Address = getScanlineNext1Address(); + const uint32_t color0 = getScanlineColor( signal, pTable ); + + /* */ *pLine1Address = color0; + /* */ *pLine0Address = color0; + /* */ g_pVideoAddress++; +} #endif //=========================================================================== @@ -685,6 +660,51 @@ inline void updatePixels( uint16_t bits ) } } +//=========================================================================== +inline void updateVideoScannerHorzEOL() +{ + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + //VIDEO_DRAW_ENDLINE(); + if (g_nColorBurstPixels < 2) + { + g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); +#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer + g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(0); +#endif + } + else + { + g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); +#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer + g_pFuncUpdateHuePixel(0); + g_pFuncUpdateHuePixel(0); + g_pFuncUpdateHuePixel(0); +#endif + } + } + + g_nVideoClockHorz = 0; + + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + if ((++g_nTextFlashCounter & 0xF) == 0) + g_nTextFlashMask ^= -1; // 16-bits + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + updateVideoScannerAddress(); + } + } +} + +//=========================================================================== inline void updateVideoScannerAddress() { g_pVideoAddress = g_pScanLines[2*g_nVideoClockVert]; @@ -693,99 +713,12 @@ inline void updateVideoScannerAddress() g_nSignalBitsNTSC = 0; } -//=========================================================================== -static void init_video_tables (void) -{ - /* - Convert 7-bit monochrome luminance to 14-bit double pixel luminance - Chroma will be applied later based on the color phase in updatePixelHueMonitorDoubleScanline( luminanceBit ) - 0x001 -> 0x0003 - 0x002 -> 0x000C - 0x004 -> 0x0030 - 0x008 -> 0x00C0 - : -> : - 0x100 -> 0x4000 - */ - for (uint8_t byte = 0; byte < 0x80; byte++ ) // Optimization: hgrbits second 128 entries are mirror of first 128 - for (uint8_t bits = 0; bits < 7; bits++ ) // high bit = half pixel shift; pre-optimization: bits < 8 - if (byte & (1 << bits)) // pow2 mask - g_aPixelDoubleMaskHGR[byte] |= 3 << (bits*2); - - for ( uint16_t color = 0; color < 16; color++ ) - g_aPixelMaskGR[ color ] = (color << 12) | (color << 8) | (color << 4) | (color << 0); -} - -// sadly float64 precision is needed -#define real double - -//=========================================================================== -static real init_signal_prefilter (real z) -{ - static real xv[NUM_SIGZEROS + 1] = { 0,0,0 }; - static real yv[NUM_SIGPOLES + 1] = { 0,0,0 }; - - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / SIGGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (-0.2718798058f * yv[0]) + (0.7465656072f * yv[1]); - - return yv[2]; -} - -//=========================================================================== -static real init_luma0_filter (real z) -{ - static real xv[NUM_LUMZEROS + 1] = { 0,0,0 }; - static real yv[NUM_LUMPOLES + 1] = { 0,0,0 }; - - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / LUMGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); - - return yv[2]; -} - -//=========================================================================== -static real init_luma1_filter (real z) -{ - static real xv[NUM_LUMZEROS + 1] = { 0,0,0}; - static real yv[NUM_LUMPOLES + 1] = { 0,0,0}; - - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / LUMGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[0] + xv[2] + (2 * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); - - return yv[2]; -} - -//=========================================================================== -static real init_chroma_filter (real z) -{ - static real xv[NUM_CHRZEROS + 1] = {0,0,0}; - static real yv[NUM_CHRPOLES + 1] = {0,0,0}; - - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / CHRGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[2] - xv[0] + (-0.7318893645f * yv[0]) + (1.2336442711f * yv[1]); - - return yv[2]; -} +// Non-Inline _________________________________________________________ // Build the 4 phase chroma lookup table // The YI'Q' colors are hard-coded //=========================================================================== -static void init_chroma_phase_table (void) +static void initChromaPhaseTables (void) { int phase,s,t,n; real z,y0,y1,c,i,q; @@ -811,10 +744,10 @@ static void init_chroma_phase_table (void) { #if CHROMA_BLUR //z = z * 1.25; - zz = init_signal_prefilter(z); - c = init_chroma_filter(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees - y0 = init_luma0_filter(zz); - y1 = init_luma1_filter(zz - c); + zz = initFilterSignal(z); + c = initFilterChroma(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + y0 = initFilterLuma0(zz); + y1 = initFilterLuma1(zz - c); #else // CHROMA_BLUR y0 = y0 + (z - y0) / 4.0; y1 = y0; // fix TV mode @@ -834,7 +767,7 @@ static void init_chroma_phase_table (void) #endif #if CHROMA_FILTER == 2 // more blur, muted chroma fringe // White has too much ringing, and the color fringes are muted - c = init_signal_prefilter(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + c = initFilterSignal(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees #endif #endif // CHROMA_BLUR c = c * 2.f; @@ -916,31 +849,106 @@ static void init_chroma_phase_table (void) } //=========================================================================== -static void updatePixelHueColorTVSingleScanline (uint16_t compositeSignal) +static real initFilterChroma (real z) { - updateFramebufferColorTVSingleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); - updateColorPhase(); + static real xv[NUM_CHRZEROS + 1] = {0,0,0}; + static real yv[NUM_CHRPOLES + 1] = {0,0,0}; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / CHRGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[2] - xv[0] + (-0.7318893645f * yv[0]) + (1.2336442711f * yv[1]); + + return yv[2]; } //=========================================================================== -static void updatePixelHueColorTVDoubleScanline (uint16_t compositeSignal) +static real initFilterLuma0 (real z) { - updateFramebufferColorTVDoubleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); - updateColorPhase(); + static real xv[NUM_LUMZEROS + 1] = { 0,0,0 }; + static real yv[NUM_LUMPOLES + 1] = { 0,0,0 }; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / LUMGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); + + return yv[2]; } //=========================================================================== -static void updatePixelHueMonitorSingleScanline (uint16_t compositeSignal) +static real initFilterLuma1 (real z) { - updateFramebufferMonitorSingleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); - updateColorPhase(); + static real xv[NUM_LUMZEROS + 1] = { 0,0,0}; + static real yv[NUM_LUMPOLES + 1] = { 0,0,0}; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / LUMGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[0] + xv[2] + (2 * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); + + return yv[2]; } //=========================================================================== -static void updatePixelHueMonitorDoubleScanline (uint16_t compositeSignal) +static real initFilterSignal (real z) { - updateFramebufferMonitorDoubleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); - updateColorPhase(); + static real xv[NUM_SIGZEROS + 1] = { 0,0,0 }; + static real yv[NUM_SIGPOLES + 1] = { 0,0,0 }; + + xv[0] = xv[1]; + xv[1] = xv[2]; + xv[2] = z / SIGGAIN; + yv[0] = yv[1]; + yv[1] = yv[2]; + yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (-0.2718798058f * yv[0]) + (0.7465656072f * yv[1]); + + return yv[2]; +} + +//=========================================================================== +static void initPixelDoubleMasks (void) +{ + /* + Convert 7-bit monochrome luminance to 14-bit double pixel luminance + Chroma will be applied later based on the color phase in updatePixelHueMonitorDoubleScanline( luminanceBit ) + 0x001 -> 0x0003 + 0x002 -> 0x000C + 0x004 -> 0x0030 + 0x008 -> 0x00C0 + : -> : + 0x100 -> 0x4000 + */ + for (uint8_t byte = 0; byte < 0x80; byte++ ) // Optimization: hgrbits second 128 entries are mirror of first 128 + for (uint8_t bits = 0; bits < 7; bits++ ) // high bit = half pixel shift; pre-optimization: bits < 8 + if (byte & (1 << bits)) // pow2 mask + g_aPixelDoubleMaskHGR[byte] |= 3 << (bits*2); + + for ( uint16_t color = 0; color < 16; color++ ) + g_aPixelMaskGR[ color ] = (color << 12) | (color << 8) | (color << 4) | (color << 0); +} + +//=========================================================================== +void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b ) +{ + for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ ) + { + g_aBnWMonitorCustom[ iSample ].b = (g_aBnWMonitor[ iSample ].b * b) >> 8; + g_aBnWMonitorCustom[ iSample ].g = (g_aBnWMonitor[ iSample ].g * g) >> 8; + g_aBnWMonitorCustom[ iSample ].r = (g_aBnWMonitor[ iSample ].r * r) >> 8; + g_aBnWMonitorCustom[ iSample ].a = 0xFF; + + g_aBnWColorTVCustom[ iSample ].b = (g_aBnwColorTV[ iSample ].b * b) >> 8; + g_aBnWColorTVCustom[ iSample ].g = (g_aBnwColorTV[ iSample ].g * g) >> 8; + g_aBnWColorTVCustom[ iSample ].r = (g_aBnwColorTV[ iSample ].r * r) >> 8; + g_aBnWColorTVCustom[ iSample ].a = 0xFF; + } } //=========================================================================== @@ -968,159 +976,31 @@ static void updatePixelBnWColorTVDoubleScanline (uint16_t compositeSignal) } //=========================================================================== -void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b ) +static void updatePixelHueColorTVSingleScanline (uint16_t compositeSignal) { - for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ ) - { - g_aBnWMonitorCustom[ iSample ].b = (g_aBnWMonitor[ iSample ].b * b) >> 8; - g_aBnWMonitorCustom[ iSample ].g = (g_aBnWMonitor[ iSample ].g * g) >> 8; - g_aBnWMonitorCustom[ iSample ].r = (g_aBnWMonitor[ iSample ].r * r) >> 8; - g_aBnWMonitorCustom[ iSample ].a = 0xFF; - - g_aBnWColorTVCustom[ iSample ].b = (g_aBnwColorTV[ iSample ].b * b) >> 8; - g_aBnWColorTVCustom[ iSample ].g = (g_aBnwColorTV[ iSample ].g * g) >> 8; - g_aBnWColorTVCustom[ iSample ].r = (g_aBnwColorTV[ iSample ].r * r) >> 8; - g_aBnWColorTVCustom[ iSample ].a = 0xFF; - } + updateFramebufferColorTVSingleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); + updateColorPhase(); } //=========================================================================== -void NTSC_SetVideoTextMode( int cols ) +static void updatePixelHueColorTVDoubleScanline (uint16_t compositeSignal) { - if( cols == 40 ) - g_pFuncUpdateTextScreen = updateScreenText40; - else - g_pFuncUpdateTextScreen = updateScreenText80; + updateFramebufferColorTVDoubleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]); + updateColorPhase(); } //=========================================================================== -void NTSC_SetVideoMode( int bVideoModeFlags ) +static void updatePixelHueMonitorSingleScanline (uint16_t compositeSignal) { - g_nVideoMixed = bVideoModeFlags & VF_MIXED; - g_nVideoCharSet = g_nAltCharSetOffset != 0; - - g_nTextPage = 1; - g_nHiresPage = 1; - if (bVideoModeFlags & VF_PAGE2) { - if (0 == (bVideoModeFlags & VF_80STORE)) { - g_nTextPage = 2; - g_nHiresPage = 2; - } - } - - if (bVideoModeFlags & VF_TEXT) { - if (bVideoModeFlags & VF_80COL) - g_pFuncUpdateGraphicsScreen = updateScreenText80; - else - g_pFuncUpdateGraphicsScreen = updateScreenText40; - } - else if (bVideoModeFlags & VF_HIRES) { - if (bVideoModeFlags & VF_DHIRES) - if (bVideoModeFlags & VF_80COL) - g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80; - else - g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires40; - else - g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40; - } - else { - if (bVideoModeFlags & VF_DHIRES) - if (bVideoModeFlags & VF_80COL) - g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80; - else - g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores40; - else - g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40; - } + updateFramebufferMonitorSingleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); + updateColorPhase(); } //=========================================================================== -void NTSC_SetVideoStyle() // (int v, int s) +static void updatePixelHueMonitorDoubleScanline (uint16_t compositeSignal) { - int half = g_uHalfScanLines; - uint8_t r, g, b; - - switch ( g_eVideoType ) - { - case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: - if (half) - { - g_pFuncUpdateBnWPixel = updatePixelBnWColorTVSingleScanline; - g_pFuncUpdateHuePixel = updatePixelHueColorTVSingleScanline; - } - else { - g_pFuncUpdateBnWPixel = updatePixelBnWColorTVDoubleScanline; - g_pFuncUpdateHuePixel = updatePixelHueColorTVDoubleScanline; - } - break; - - case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1: - default: - if (half) - { - g_pFuncUpdateBnWPixel = updatePixelBnWMonitorSingleScanline; - g_pFuncUpdateHuePixel = updatePixelHueMonitorSingleScanline; - } - else { - g_pFuncUpdateBnWPixel = updatePixelBnWMonitorDoubleScanline; - g_pFuncUpdateHuePixel = updatePixelHueMonitorDoubleScanline; - } - break; - - case VT_COLOR_TEXT_OPTIMIZED: // VT_MONO_TV: //2: - r = 0xFF; - g = 0xFF; - b = 0xFF; - updateMonochromeTables( r, g, b ); // Custom Monochrome color - if (half) - { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVSingleScanline; - } - else { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVDoubleScanline; - } - break; - -// case VT_MONO_WHITE: //VT_MONO_MONITOR: //3: - case VT_MONO_AMBER: - r = 0xFF; - g = 0x80; - b = 0x00; - goto _mono; - - case VT_MONO_GREEN: - r = 0x00; - g = 0xC0; - b = 0x00; - goto _mono; - - case VT_MONO_WHITE: - r = 0xFF; - g = 0xFF; - b = 0xFF; - goto _mono; - - case VT_MONO_HALFPIXEL_REAL: - // From WinGDI.h - // #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) - //#define GetRValue(rgb) (LOBYTE(rgb)) - //#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) - //#define GetBValue(rgb) (LOBYTE((rgb)>>16)) - r = (g_nMonochromeRGB >> 0) & 0xFF; - g = (g_nMonochromeRGB >> 8) & 0xFF; - b = (g_nMonochromeRGB >> 16) & 0xFF; -_mono: - updateMonochromeTables( r, g, b ); // Custom Monochrome color - if (half) - { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorSingleScanline; - } - else - { - g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorDoubleScanline; - } - break; - } + updateFramebufferMonitorDoubleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]); + updateColorPhase(); } //=========================================================================== @@ -1414,20 +1294,160 @@ void updateScreenText80 (long cycles6502) } } +// Functions (Public) _________________________________________________ + //=========================================================================== -unsigned char NTSC_VideoByte (unsigned long cycles6502) +void NTSC_SetVideoTextMode( int cols ) { - unsigned char * mem; - mem = MemGetMainPtr(g_aHorzClockMemAddress[ g_nVideoClockHorz ]); - return mem[0]; + if( cols == 40 ) + g_pFuncUpdateTextScreen = updateScreenText40; + else + g_pFuncUpdateTextScreen = updateScreenText80; +} + +//=========================================================================== +void NTSC_SetVideoMode( int bVideoModeFlags ) +{ + g_nVideoMixed = bVideoModeFlags & VF_MIXED; + g_nVideoCharSet = g_nAltCharSetOffset != 0; + + g_nTextPage = 1; + g_nHiresPage = 1; + if (bVideoModeFlags & VF_PAGE2) { + if (0 == (bVideoModeFlags & VF_80STORE)) { + g_nTextPage = 2; + g_nHiresPage = 2; + } + } + + if (bVideoModeFlags & VF_TEXT) { + if (bVideoModeFlags & VF_80COL) + g_pFuncUpdateGraphicsScreen = updateScreenText80; + else + g_pFuncUpdateGraphicsScreen = updateScreenText40; + } + else if (bVideoModeFlags & VF_HIRES) { + if (bVideoModeFlags & VF_DHIRES) + if (bVideoModeFlags & VF_80COL) + g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80; + else + g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires40; + else + g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40; + } + else { + if (bVideoModeFlags & VF_DHIRES) + if (bVideoModeFlags & VF_80COL) + g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80; + else + g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores40; + else + g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40; + } +} + +//=========================================================================== +void NTSC_SetVideoStyle() // (int v, int s) +{ + int half = g_uHalfScanLines; + uint8_t r, g, b; + + switch ( g_eVideoType ) + { + case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: + if (half) + { + g_pFuncUpdateBnWPixel = updatePixelBnWColorTVSingleScanline; + g_pFuncUpdateHuePixel = updatePixelHueColorTVSingleScanline; + } + else { + g_pFuncUpdateBnWPixel = updatePixelBnWColorTVDoubleScanline; + g_pFuncUpdateHuePixel = updatePixelHueColorTVDoubleScanline; + } + break; + + case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1: + default: + if (half) + { + g_pFuncUpdateBnWPixel = updatePixelBnWMonitorSingleScanline; + g_pFuncUpdateHuePixel = updatePixelHueMonitorSingleScanline; + } + else { + g_pFuncUpdateBnWPixel = updatePixelBnWMonitorDoubleScanline; + g_pFuncUpdateHuePixel = updatePixelHueMonitorDoubleScanline; + } + break; + + case VT_COLOR_TEXT_OPTIMIZED: // VT_MONO_TV: //2: + r = 0xFF; + g = 0xFF; + b = 0xFF; + updateMonochromeTables( r, g, b ); // Custom Monochrome color + if (half) + { + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVSingleScanline; + } + else { + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVDoubleScanline; + } + break; + +// case VT_MONO_WHITE: //VT_MONO_MONITOR: //3: + case VT_MONO_AMBER: + r = 0xFF; + g = 0x80; + b = 0x00; + goto _mono; + + case VT_MONO_GREEN: + r = 0x00; + g = 0xC0; + b = 0x00; + goto _mono; + + case VT_MONO_WHITE: + r = 0xFF; + g = 0xFF; + b = 0xFF; + goto _mono; + + case VT_MONO_HALFPIXEL_REAL: + // From WinGDI.h + // #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) + //#define GetRValue(rgb) (LOBYTE(rgb)) + //#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) + //#define GetBValue(rgb) (LOBYTE((rgb)>>16)) + r = (g_nMonochromeRGB >> 0) & 0xFF; + g = (g_nMonochromeRGB >> 8) & 0xFF; + b = (g_nMonochromeRGB >> 16) & 0xFF; +_mono: + updateMonochromeTables( r, g, b ); // Custom Monochrome color + if (half) + { + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorSingleScanline; + } + else + { + g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorDoubleScanline; + } + break; + } +} + +//=========================================================================== +uint8_t NTSC_VideoGetByte (unsigned long cycles6502) +{ + uint8_t *pMain = MemGetMainPtr( g_aHorzClockMemAddress[ g_nVideoClockHorz ] ); + return pMain[0]; } //=========================================================================== void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit { make_csbits(); - init_video_tables(); - init_chroma_phase_table(); + initPixelDoubleMasks(); + initChromaPhaseTables(); updateMonochromeTables( 0xFF, 0xFF, 0xFF ); for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) @@ -1497,7 +1517,7 @@ void NTSC_VideoInitAppleType () } //=========================================================================== -int NTSC_VideoIsVbl () +bool NTSC_VideoIsVbl () { return (g_nVideoClockVert >= VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockVert < VIDEO_SCANNER_MAX_VERT); } diff --git a/source/NTSC.h b/source/NTSC.h index f693d2cc..5b98d53d 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -10,10 +10,9 @@ extern void NTSC_SetVideoMode( int flags ); extern void NTSC_SetVideoStyle(); - extern uint8_t NTSC_VideoByte(unsigned long); - extern void NTSC_VideoCreateDIBSection(); + extern uint8_t NTSC_VideoGetByte(unsigned long); extern void NTSC_VideoInit( uint8_t *pFramebuffer ); extern void NTSC_VideoInitAppleType (); - extern int NTSC_VideoIsVbl(); + extern bool NTSC_VideoIsVbl(); extern void NTSC_VideoUpdateCycles( long cycles ); From f36073beb5d7d15b5d05adfdd28507e2ccb89cdc Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 21:01:01 -0800 Subject: [PATCH 046/121] Start cleanup Video --- source/Video.cpp | 115 ++++++++--------------------------------------- 1 file changed, 18 insertions(+), 97 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index e7bb4b3d..80486c0a 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -306,8 +306,6 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) // Prototypes (Private) _____________________________________________ - void V_CreateLookup_Lores (); - // Monochrome Half-Pixel Support void V_CreateLookup_MonoHiResHalfPixel_Real (); @@ -323,16 +321,7 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) int GetMonochromeIndex(); void V_CreateIdentityPalette (); - void V_CreateDIBSections (); - -/** Our BitBlit() / VRAM_Copy() - @param dx Dst X - @param dy Dst Y - @param w Width (same for src & dst) - @param h Height (same for src & dst) - @param sx Src X - @param sy Src Y -// =========================================================================== */ + void videoCreateDIBSection(); //=========================================================================== void CreateFrameOffsetTable (LPBYTE addr, LONG pitch) @@ -377,23 +366,7 @@ void VideoInitialize () g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB; g_pFramebufferinfo->bmiHeader.biClrUsed = 0; - NTSC_VideoCreateDIBSection(); -} - -//=========================================================================== -int GetMonochromeIndex() -{ - int iMonochrome; - - switch (g_eVideoType) - { - case VT_MONO_AMBER : iMonochrome = MONOCHROME_AMBER ; break; - case VT_MONO_GREEN : iMonochrome = MONOCHROME_GREEN ; break; - case VT_MONO_WHITE : iMonochrome = HGR_WHITE ; break; - default : iMonochrome = MONOCHROME_CUSTOM; break; // caller will use MONOCHROME_CUSTOM MONOCHROME_CUSTOM_50 ! - } - - return iMonochrome; + videoCreateDIBSection(); } //=========================================================================== @@ -468,18 +441,6 @@ void V_CreateIdentityPalette () } #if 0 -//=========================================================================== -void V_CreateLookup_HiResHalfPixel_Authentic () // Colors are solid (100% coverage) -{ - // 2-bits from previous byte, 2-bits from next byte = 2^4 = 16 total permutations - for (int iColumn = 0; iColumn < 16; iColumn++) - { - int offsetx = iColumn << 5; // every column is 32 bytes wide -- 7 apple pixels = 14 pixels + 2 pad + 14 pixels + 2 pad - - for (unsigned iByte = 0; iByte < 256; iByte++) - { - int aPixels[11]; // c2 c1 b7 b6 b5 b4 b3 b2 b1 b0 c8 c4 - /* aPixel[i] A 9|8 7 6 5 4 3 2|1 0 @@ -511,7 +472,19 @@ Legend: int x = 0; int y = iByte << 1; -/* Test cases +/* +Color Reference Tests: + +2000:D5 AA D5 AA D5 AA // blue blue blue +2400:AA D5 2A 55 55 2A //+ red green violet +// //= grey aqua violet + +2C00:AA D5 AA D5 2A 55 // red red green +3000:2A 55 55 2A 55 2A //+ green violet violet +// //= yellow pink grey + +Test cases +========== 81 blue 2000:D5 AA D5 AA 82 orange @@ -527,11 +500,6 @@ Legend: Edge Case for Color Bleed ! 2000:40 00 2400:40 80 -*/ - - // Fixup missing pixels that normally have been scan-line shifted -- Apple "half-pixel" -- but cross 14-pixel boundaries. - if( hibit ) - { // Test Patterns // 81 blue @@ -557,24 +525,13 @@ Legend: // or // 2000:A0 83 orange should "bleed" thru // 2400:B0 83 should have black gap - - if ( aPixels[2] ) -#if HALF_PIXEL_BLEED // No Half-Pixel Bleed SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , DARK_BLUE ); // Gumball: 229A: AB A9 87 SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , BROWN ); // half luminance red Elite: 2444: BB F7 SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, BROWN ); // half luminance red Gumball: 218E: AA 97 SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5 SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5 -#else -// "Text optimized" IF this pixel on, and adjacent right pixel off, then colorize first half-pixel of this byte - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5 - SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5 -#endif // HALF_PIXEL_BLEED // Test Pattern: Ultima 4 Logo - Castle // 3AC8: 36 5B 6D 36 -} - - /* Address Binary -> Displayed 2000:01 0---0001 -> 1 0 0 0 column 1 2400:81 1---0001 -> 1 0 0 0 half-pixel shift right @@ -590,10 +547,6 @@ Legend: @reference: see Beagle Bro's Disk: "Silicon Salad", File: DOUBLE HI-RES Fortunately double-hires is supported via pixel doubling, so we can do half-pixel shifts ;-) - */ - - // Fixup missing pixels that normally have been scan-line shifted -- Apple "half-pixel" -- but cross 14-pixel boundaries. - /* Test Cases // Games Archon Logo Gumball (at Machine) @@ -606,7 +559,7 @@ Legend: C050 C052 C057 2000:D0 80 00 2800:80 D0 00 - */ +*/ #endif // google: CreateDIBPatternBrushPt @@ -642,25 +595,6 @@ static void CreateLookup_TextCommon(HDC hDstDC, DWORD rop) DeleteObject(hCharBitmap[i]); } -//=========================================================================== -void SetLastDrawnImage () -{ - memcpy(vidlastmem+0x400,g_pTextBank0,0x400); - - if (SW_HIRES) - memcpy(vidlastmem+0x2000,g_pHiresBank0,0x2000); - if (SW_DHIRES && SW_HIRES) - memcpy(vidlastmem,g_pHiresBank1,0x2000); - else if (SW_80COL) // Don't test for !SW_HIRES, as some 80-col text routines have SW_HIRES set (Bug #8300) - memcpy(vidlastmem,g_pTextBank1,0x400); - - int loop; - for (loop = 0; loop < 256; loop++) - { - *(memdirty+loop) &= ~2; - } -} - //=========================================================================== static inline int GetOriginal2EOffset(BYTE ch) @@ -669,20 +603,6 @@ static inline int GetOriginal2EOffset(BYTE ch) return !IsOriginal2E() || !g_nAltCharSetOffset || (ch<0x40) || (ch>0x5F) ? 0 : -g_nAltCharSetOffset; } -/* - -Color Reference Tests: - -2000:D5 AA D5 AA D5 AA // blue blue blue -2400:AA D5 2A 55 55 2A //+ red green violet -// //= grey aqua violet - -2C00:AA D5 AA D5 2A 55 // red red green -3000:2A 55 55 2A 55 2A //+ green violet violet -// //= yellow pink grey - -*/ - //=========================================================================== #define ROL_NIB(x) ( (((x)<<1)&0xF) | (((x)>>3)&1) ) @@ -978,6 +898,7 @@ BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) BYTE VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) { bool bVblBar = VideoGetVbl(uExecutedCycles); + //bool bVblBar = NTSC_VideoIsVbl(); BYTE r = KeybGetKeycode(); return (r & ~0x80) | (bVblBar ? 0x80 : 0); @@ -1919,7 +1840,7 @@ void Config_Save_Video() // ____________________________________________________________________ //=========================================================================== -void NTSC_VideoCreateDIBSection() +void videoCreateDIBSection() { // CREATE THE DEVICE CONTEXT HWND window = GetDesktopWindow(); From b96b3fe1d46f54751ad610ef5418f64e4e288e30 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Fri, 2 Jan 2015 21:28:01 -0800 Subject: [PATCH 047/121] Optimization: replace slow VideoGetVbl() with fast NTSC_VideoIsVbl() --- source/Video.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index 80486c0a..9332039e 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -897,8 +897,8 @@ BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) BYTE VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) { - bool bVblBar = VideoGetVbl(uExecutedCycles); - //bool bVblBar = NTSC_VideoIsVbl(); + //bool bVblBar = VideoGetVbl(uExecutedCycles); + bool bVblBar = NTSC_VideoIsVbl(); BYTE r = KeybGetKeycode(); return (r & ~0x80) | (bVblBar ? 0x80 : 0); From ce94b596637dac685cb4008f66267e5b461559ea Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 03:31:19 -0800 Subject: [PATCH 048/121] Bug #241 - AppleWin 1.26 NTSC -- Fix "ANSI STORY" so horz scroll works, fix vert scroll so it mostly works, verified "Rainbow" works --- source/Memory.cpp | 17 ++++++++- source/NTSC.cpp | 97 ++++++++++++++++++++++++++++++++++++++++------- source/Video.cpp | 65 +++---------------------------- source/Video.h | 3 +- 4 files changed, 105 insertions(+), 77 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 3868e0b2..05ae1d9a 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -38,6 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Memory.h" #include "Mockingboard.h" #include "MouseInterface.h" +#include "NTSC.h" #include "NoSlotClock.h" #include "ParallelPrinter.h" #include "Registry.h" @@ -230,7 +231,7 @@ static BYTE __stdcall IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return VideoCheckVbl(pc, addr, bWrite, d, nCyclesLeft); + case 0x9: return VideoCheckVbl( nCyclesLeft ); // NTSC cleanup case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); @@ -1477,13 +1478,25 @@ void MemResetPaging() BYTE MemReadFloatingBus(const ULONG uExecutedCycles) { - return*(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); + // NTSC: It is tempting to replace with + // return NTSC_VideoGetByte( uExecutedCycles ); + // But that breaks "Rainbow" Bug #254 + // Why is this out of sync?? + //uint8_t val1 = NTSC_VideoGetByte( uExecutedCycles ); + //uint8_t val2 = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); + //if( val1 != val2 ) mem[ 0x2000 ] ^= 0xFF; + + return *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); } //=========================================================================== BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles) { + // NTSC: It is tempting to replace with + // return NTSC_VideoGetByte( uExecutedCycles ); + // But that breaks "Rainbow" Bug #254 + // BYTE r= NTSC_VideoGetByte( uExecutedCycles ); BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); return (r & ~0x80) | ((highbit) ? 0x80 : 0); } diff --git a/source/NTSC.cpp b/source/NTSC.cpp index f058a3dd..6c22c88b 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -65,7 +65,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #endif #endif - // Types struct ColorSpace_PAL_t // Phase Amplitute Luma @@ -142,6 +141,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static UpdateScreenFunc_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; static UpdateScreenFunc_t g_pFuncUpdateTextScreen = 0; // updateScreenText40; static UpdateScreenFunc_t g_pFuncUpdateGraphicsScreen = 0; // updateScreenText40; + static UpdateScreenFunc_t g_pFuncModeSwitchDelayed = 0; + + static UpdateScreenFunc_t g_aFuncUpdateHorz [VIDEO_SCANNER_MAX_HORZ]; // ANSI STORY: DGR80/TEXT80 vert/horz scrolll switches video mode mid-scan line! + static uint32_t g_aHorzClockVideoMode [VIDEO_SCANNER_MAX_HORZ]; // ANSI STORY: DGR80/TEXT80 vert/horz scrolll switches video mode mid-scan line! typedef void (*UpdatePixelFunc_t)(uint16_t); static UpdatePixelFunc_t g_pFuncUpdateBnWPixel = 0; //updatePixelBnWMonitorSingleScanline; @@ -404,6 +407,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ); inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ); inline void updatePixels( uint16_t bits ); + inline bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self ); inline void updateVideoScannerHorzEOL(); inline void updateVideoScannerAddress(); @@ -660,6 +664,25 @@ inline void updatePixels( uint16_t bits ) } } +//=========================================================================== +inline bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self ) +{ + bool bBail = false; + if( g_aHorzClockVideoMode[ g_nVideoClockHorz ] != g_aHorzClockVideoMode[ g_nVideoClockHorz+1 ] && !g_nVideoMixed ) // !g_nVideoMixed for "Rainbow" + { + UpdateScreenFunc_t pFunc = g_aFuncUpdateHorz[ g_nVideoClockHorz ]; + if( pFunc && pFunc != self ) + { + g_pFuncUpdateGraphicsScreen = pFunc; +// g_pFuncUpdateTextScreen = pFunc; // No, as we can't break mixed mode for "Rainbow" + pFunc( cycles6502 ); + bBail = true; + } + } + + return bBail; +} + //=========================================================================== inline void updateVideoScannerHorzEOL() { @@ -711,6 +734,12 @@ inline void updateVideoScannerAddress() g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; g_nSignalBitsNTSC = 0; + + // ANSI STORY: clear mode and pointer to draw func + memset( g_aFuncUpdateHorz , 0, sizeof( g_aFuncUpdateHorz ) ); + memset( g_aHorzClockVideoMode, 0, sizeof( g_aHorzClockVideoMode ) ); + + g_aFuncUpdateHorz[0] = g_pFuncUpdateGraphicsScreen; } // Non-Inline _________________________________________________________ @@ -1014,7 +1043,7 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 return; } - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressHGR(); @@ -1026,6 +1055,8 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleHires40 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 @@ -1048,7 +1079,7 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires return; } - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressHGR(); @@ -1060,6 +1091,8 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleHires80 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t *pAux = MemGetAuxPtr(ad); @@ -1087,7 +1120,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores return; } - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressTXT(); @@ -1099,6 +1132,8 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleLores40 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; uint16_t lo = getLoResBits( m ); @@ -1121,7 +1156,7 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores return; } - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressTXT(); @@ -1133,6 +1168,8 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if( updateScanLineModeSwitch( cycles6502, updateScreenDoubleLores80 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t *pAux = MemGetAuxPtr(ad); @@ -1147,9 +1184,11 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores uint16_t bits = (main << 7) | (aux & 0x7f); updatePixels( bits ); g_nLastColumnPixelNTSC = (bits >> 14) & 3; + } } updateVideoScannerHorzEOL(); + } } @@ -1164,7 +1203,7 @@ void updateScreenSingleHires40 (long cycles6502) return; } - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressHGR(); @@ -1176,6 +1215,8 @@ void updateScreenSingleHires40 (long cycles6502) } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if ( updateScanLineModeSwitch( cycles6502, updateScreenSingleHires40 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 @@ -1199,7 +1240,7 @@ void updateScreenSingleLores40 (long cycles6502) return; } - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressTXT(); @@ -1211,6 +1252,8 @@ void updateScreenSingleLores40 (long cycles6502) } else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if( updateScanLineModeSwitch( cycles6502, updateScreenSingleLores40 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; uint16_t lo = getLoResBits( m ); @@ -1227,7 +1270,7 @@ void updateScreenText40 (long cycles6502) { unsigned ad; - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressTXT(); @@ -1240,6 +1283,8 @@ void updateScreenText40 (long cycles6502) { if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if ( updateScanLineModeSwitch( cycles6502, updateScreenText40 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pMain = MemGetMainPtr(ad); uint8_t m = pMain[0]; uint8_t c = getCharSetBits(m); @@ -1247,6 +1292,7 @@ void updateScreenText40 (long cycles6502) if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) bits ^= g_nTextFlashMask; updatePixels( bits ); + } } updateVideoScannerHorzEOL(); @@ -1258,7 +1304,7 @@ void updateScreenText80 (long cycles6502) { unsigned int ad; - for (; cycles6502; --cycles6502) + for (; cycles6502 > 0; --cycles6502) { UpdateVideoAddressTXT(); @@ -1271,6 +1317,8 @@ void updateScreenText80 (long cycles6502) { if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { + if ( updateScanLineModeSwitch( cycles6502, updateScreenText80 ) ) return; // ANSI STORY: vide mode switch mid scan line! + uint8_t *pAux = MemGetAuxPtr(ad); uint8_t *pMain = MemGetMainPtr(ad); @@ -1308,6 +1356,11 @@ void NTSC_SetVideoTextMode( int cols ) //=========================================================================== void NTSC_SetVideoMode( int bVideoModeFlags ) { + int h = g_nVideoClockHorz; +// int h = (g_dwCyclesThisFrame + 40) % 65; + + g_aHorzClockVideoMode[ h ] = bVideoModeFlags; + g_nVideoMixed = bVideoModeFlags & VF_MIXED; g_nVideoCharSet = g_nAltCharSetOffset != 0; @@ -1320,6 +1373,8 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) } } + UpdateScreenFunc_t pPrevUpdate = g_pFuncUpdateGraphicsScreen; + if (bVideoModeFlags & VF_TEXT) { if (bVideoModeFlags & VF_80COL) g_pFuncUpdateGraphicsScreen = updateScreenText80; @@ -1344,6 +1399,16 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) else g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40; } +#if 0 + g_aFuncUpdateHorz[ g_nVideoClockHorz ] = g_pFuncUpdateGraphicsScreen; // ANSI STORY + + if( g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START ) + g_pFuncUpdateGraphicsScreen = pPrevUpdate; + else + g_aFuncUpdateHorz[0] = g_pFuncUpdateGraphicsScreen; +#else + g_aFuncUpdateHorz[ h ] = g_pFuncUpdateGraphicsScreen; // NTSC: ANSI STORY +#endif } //=========================================================================== @@ -1514,6 +1579,10 @@ void NTSC_VideoInitAppleType () g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; else g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; + + g_nVideoClockVert = 0; + g_nVideoClockHorz = 0; + } //=========================================================================== @@ -1528,10 +1597,11 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) { bool bRedraw = cycles6502 >= VIDEO_SCANNER_6502_CYCLES; -// if( g_bFullSpeed ) -// g_pFuncUpdateGraphicsScreen( cycles6502 ); -// else - +// if( !g_bFullSpeed ) +if(true) + g_pFuncUpdateGraphicsScreen( cycles6502 ); + else +{ while( cycles6502 > VIDEO_SCANNER_6502_CYCLES ) /* */ cycles6502 -= VIDEO_SCANNER_6502_CYCLES ; @@ -1567,3 +1637,4 @@ void NTSC_VideoUpdateCycles( long cycles6502 ) g_pFuncUpdateGraphicsScreen( nCyclesVBlank ); } } +} diff --git a/source/Video.cpp b/source/Video.cpp index 9332039e..41c10985 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -227,8 +227,6 @@ int const kVLine0State = 0x100; // V[543210CBA] = 100000000 int const kVPresetLine = 256; // line when V state presets int const kVSyncLines = 4; // lines per VSync duration -static BYTE celldirty[40][32]; // [TC: 27/06/2014] NB. No longer used! -// NUM_COLOR_PALETTE static COLORREF customcolors[256]; // MONOCHROME is last custom color static HBITMAP g_hDeviceBitmap; @@ -249,14 +247,6 @@ static LPBYTE g_aSourceStartofLine[ MAX_SOURCE_Y ]; static LPBYTE g_pTextBank1; // Aux static LPBYTE g_pTextBank0; // Main -// For tv emulation HGR Video Mode -// 2 extra scan lines on bottom? -static BYTE hgrpixelmatrix[FRAMEBUFFER_W/2][FRAMEBUFFER_H/2 + 2 * HGR_MATRIX_YOFFSET]; -static BYTE colormixbuffer[6]; -static WORD colormixmap[6][6][6]; -// - - static /*bool*/ UINT g_VideoForceFullRedraw = 1; static bool g_bVideoUpdatedThisFrame = false; @@ -895,10 +885,12 @@ BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) */ -BYTE VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) +BYTE VideoCheckVbl ( ULONG uExecutedCycles ) { - //bool bVblBar = VideoGetVbl(uExecutedCycles); - bool bVblBar = NTSC_VideoIsVbl(); + bool bVblBar = VideoGetVbl(uExecutedCycles); + // NTSC: It is tempting to replace with + // bool bVblBar = NTSC_VideoIsVbl(); + // But this breaks "ANSI STORY" BYTE r = KeybGetKeycode(); return (r & ~0x80) | (bVblBar ? 0x80 : 0); @@ -1080,47 +1072,6 @@ void VideoDisplayLogo () //=========================================================================== void VideoRealizePalette(HDC dc) { -#if 0 - if( g_bIsFullScreen ) - { - if( !g_pDDPal ) - { - PALETTEENTRY aPal[256]; - - BYTE *pSrc = ((BYTE*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER); - BYTE *pDst = ((BYTE*)aPal); - - int iPal; - for(iPal = 0; iPal < 256; iPal++ ) - { - *(pDst + 0) = *(pSrc + 2); // BGR -> RGB - *(pDst + 1) = *(pSrc + 1); - *(pDst + 2) = *(pSrc + 0); - *(pDst + 3) = 0; - pDst += 4; - pSrc += 4; - } - if (g_pDD->CreatePalette(DDPCAPS_8BIT, aPal, &g_pDDPal, NULL) != DD_OK) - { - g_pDDPal = NULL; - } - } - - if (g_pDDPal) - { - g_pDDPrimarySurface->SetPalette(g_pDDPal); // this sets the palette for the primary surface - } - } - else - { - if (g_hPalette) - { - SelectPalette(dc,g_hPalette,0); - RealizePalette(dc); - } - } -#endif - if (g_hPalette) { SelectPalette(dc,g_hPalette,0); @@ -1137,12 +1088,6 @@ void VideoRedrawScreen () VideoRefreshScreen( g_uVideoMode ); } -//=========================================================================== -void _Video_Dirty() -{ - ZeroMemory(celldirty,40*32); -} - //=========================================================================== int _Video_SetupBanks( bool bBank2 ) { diff --git a/source/Video.h b/source/Video.h index ca75cc14..090b9cad 100644 --- a/source/Video.h +++ b/source/Video.h @@ -94,7 +94,6 @@ bool VideoGetSWAltCharSet(void); void VideoSetForceFullRedraw(void); -void _Video_Dirty(); int _Video_SetupBanks( bool bBank2 ); bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset); bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset); @@ -116,7 +115,7 @@ void Video_TakeScreenShot( int iScreenShotType ); // Win32/MSVC: __stdcall BYTE VideoCheckMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); -BYTE VideoCheckVbl (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); +BYTE VideoCheckVbl ( ULONG uExecutedCycles ); BYTE VideoSetMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); void Config_Load_Video(void); From 801fa4db03fb610b872fb4363e627d1fbd6cf091 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 11:42:00 -0800 Subject: [PATCH 049/121] don't call unused VideoEndOfVideoFrame, directly call VideoRefreshScreen(0) --- source/Applewin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index da9542af..debd4d47 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -231,7 +231,6 @@ void ContinueExecution(void) { g_dwCyclesThisFrame -= dwClksPerFrame; - // VideoEndOfVideoFrame(); // NTSC_TODO: is this still required? updates flash: if ((SW_TEXT || SW_MIXED) ) g_bTextFlashFlag = true VideoRefreshScreen(0); // Just copy the output of our Apple framebuffer to the system Back Buffer MB_EndOfVideoFrame(); } From 2db3c6b318c4503cb0285d26a84833e2daf6d1cb Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 11:44:06 -0800 Subject: [PATCH 050/121] PreAlpha: v12, revert VideoBenchmark() to call VideoRefreshScreen(0) --- source/Video.cpp | 70 +++++++----------------------------------------- 1 file changed, 9 insertions(+), 61 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index 41c10985..f3105112 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -248,7 +248,6 @@ static LPBYTE g_pTextBank1; // Aux static LPBYTE g_pTextBank0; // Main static /*bool*/ UINT g_VideoForceFullRedraw = 1; -static bool g_bVideoUpdatedThisFrame = false; static LPBYTE framebufferaddr = (LPBYTE)0; static LONG g_nFrameBufferPitch = 0; @@ -261,10 +260,6 @@ static UINT g_uVideoMode = VF_TEXT; DWORD g_eVideoType = VT_COLOR_TVEMU; DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look - -static bool g_bTextFlashState = false; -static bool g_bTextFlashFlag = false; - static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) //------------------------------------- @@ -665,6 +660,7 @@ void VideoBenchmark () { // GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO // SIMULATE THE ACTIVITY OF AN AVERAGE GAME DWORD totaltextfps = 0; + g_uVideoMode = VF_TEXT; FillMemory(mem+0x400,0x400,0x14); VideoRedrawScreen(); @@ -677,7 +673,7 @@ void VideoBenchmark () { FillMemory(mem+0x400,0x400,0x14); else CopyMemory(mem+0x400,mem+((cycle & 2) ? 0x4000 : 0x6000),0x400); - VideoRedrawScreen(); // VideoRefreshScreen(); + VideoRefreshScreen(0); if (cycle++ >= 3) cycle = 0; totaltextfps++; @@ -699,7 +695,7 @@ void VideoBenchmark () { FillMemory(mem+0x2000,0x2000,0x14); else CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); - VideoRedrawScreen(); // VideoRefreshScreen(); + VideoRefreshScreen(0); if (cycle++ >= 3) cycle = 0; totalhiresfps++; @@ -1048,18 +1044,18 @@ void VideoDisplayLogo () // NTSC Alpha Version DeleteObject(font); font = CreateFontA( - -56,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, + -48,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, VARIABLE_PITCH | 4 | FF_SWISS, TEXT("Arial") ); SelectObject(hFrameDC,font); - sprintf( szVersion, "NTSC ALPHA v11" ); + sprintf( szVersion, "NTSC Alpha v12 AnsiStory" ); xoff = 0; yoff = 0; - DRAWVERSION( 2, -158*scale,RGB(0x00,0x00,0x00)); - DRAWVERSION( 1, -157*scale,RGB(0x00,0x00,0x00)); - DRAWVERSION( 0, -156*scale,RGB(0xFF,0x00,0xFF)); + DRAWVERSION( 42, -158*scale,RGB(0x00,0x00,0x00)); + DRAWVERSION( 41, -157*scale,RGB(0x00,0x00,0x00)); + DRAWVERSION( 40, -156*scale,RGB(0xFF,0x00,0xFF)); // NTSC END #undef DRAWVERSION @@ -1172,7 +1168,6 @@ void VideoResetState () g_nAltCharSetOffset = 0; g_uVideoMode = VF_TEXT; g_VideoForceFullRedraw = 1; - g_bVideoUpdatedThisFrame = false; } @@ -1207,6 +1202,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) // NTSC_BEGIN NTSC_SetVideoMode( g_uVideoMode ); // NTSC_END + #if 0 // NTSC_CLEANUP: Is this still needed?? if (SW_80STORE) g_uVideoMode &= ~VF_PAGE2; @@ -1236,54 +1232,6 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) //=========================================================================== -// Called at 60Hz (every 16.666ms) -static void VideoUpdateFlash() -{ - static UINT nTextFlashCnt = 0; - - // Flash rate: - // . NTSC : 60/16 ~= 4Hz - // . PAL : 50/16 ~= 3Hz - nTextFlashCnt = (nTextFlashCnt+1) & 0xf; - - // BUG: In unthrottled CPU mode, flash rate should not be affected - if(nTextFlashCnt == 0) - { - g_bTextFlashState = !g_bTextFlashState; - - // Redraw any FLASHing chars if any text showing. NB. No FLASH g_nAppMode for 80 cols - if ((SW_TEXT || SW_MIXED) ) // && !SW_80COL) // FIX: FLASH 80-Column - g_bTextFlashFlag = true; - } -} - -//=========================================================================== - -// Called from main-loop every 17030 cycles (ie. 60Hz when CPU = 1MHz) -void VideoEndOfVideoFrame(void) -{ - g_bVideoUpdatedThisFrame = false; // Allow page1/2 toggle to result in an immediate video redraw - - VideoUpdateFlash(); // TODO: Flash rate should be constant (regardless of CPU speed) - - if (!VideoApparentlyDirty()) - return; - - // Apple II is not page flipping... - - static DWORD dwLastTime = 0; - DWORD dwCurrTime = GetTickCount(); - if (!g_bFullSpeed || - (dwCurrTime-dwLastTime >= 100)) // FullSpeed: update every 100ms - { - // Required or else screen won't update -- Sheldon's NTSC doesn't have VideoEndOfVideoFrame -- simply calls wsVideoRefresh() - VideoRedrawScreen(); // VideoRefreshScreen(); - dwLastTime = dwCurrTime; - } -} - -//=========================================================================== - bool VideoGetSW80COL(void) { return SW_80COL ? true : false; From db79b4584b016a0541f742f936b14bdb9ab82347 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 11:45:44 -0800 Subject: [PATCH 051/121] Cleanup: Factor updateFlashRate --- source/NTSC.cpp | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 6c22c88b..93865ed9 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -402,6 +402,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA inline uint32_t* getScanlinePrev2Address(); inline uint32_t* getScanlineThis0Address(); inline void updateColorPhase(); + inline void updateFlashRate(); inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ); inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ); inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ); @@ -497,6 +498,24 @@ inline void updateColorPhase() g_nColorPhaseNTSC &= 3; } +//=========================================================================== +inline void updateFlashRate() // TODO: Flash rate should be constant (regardless of CPU speed) +{ + // BUG: In unthrottled CPU mode, flash rate should not be affected + + // Flash rate: + // . NTSC : 60/16 ~= 4Hz + // . PAL : 50/16 ~= 3Hz + if ((++g_nTextFlashCounter & 0xF) == 0) + g_nTextFlashMask ^= -1; // 16-bits + + // The old way to handle flashing was + // if ((SW_TEXT || SW_MIXED) ) // && !SW_80COL) // FIX: FLASH 80-Column + // g_nTextFlashMask = true; + // The new way is to check the active char set, inlined: + // if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) // Flash only if mousetext not active +} + #if 0 #define updateFramebufferMonitorSingleScanline(signal,table) \ do { \ @@ -716,8 +735,9 @@ inline void updateVideoScannerHorzEOL() if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { g_nVideoClockVert = 0; - if ((++g_nTextFlashCounter & 0xF) == 0) - g_nTextFlashMask ^= -1; // 16-bits + + updateFlashRate(); + //VideoRefreshScreen(0); // ContinueExecution() calls VideoRefreshScreen(0) ever dwClksPerFrame (17030) } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) @@ -1289,8 +1309,10 @@ void updateScreenText40 (long cycles6502) uint8_t m = pMain[0]; uint8_t c = getCharSetBits(m); uint16_t bits = g_aPixelDoubleMaskHGR[c & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 - if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) + + if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) // Flash only if mousetext not active bits ^= g_nTextFlashMask; + updatePixels( bits ); } @@ -1328,10 +1350,10 @@ void updateScreenText80 (long cycles6502) uint16_t main = getCharSetBits( m ); uint16_t aux = getCharSetBits( a ); - if ((0 == g_nVideoCharSet) && 0x40 == (m & 0xC0)) + if ((0 == g_nVideoCharSet) && 0x40 == (m & 0xC0)) // Flash only if mousetext not active main ^= g_nTextFlashMask; - if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) + if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) // Flash only if mousetext not active aux ^= g_nTextFlashMask; uint16_t bits = (main << 7) | aux; @@ -1617,8 +1639,8 @@ if(true) if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) { g_nVideoClockVert = 0; - if ((++g_nTextFlashCounter & 0xF) == 0) - g_nTextFlashMask ^= -1; // 16-bits + + updateFlashRate(); bRedraw = true; } @@ -1635,6 +1657,8 @@ if(true) int nCyclesVBlank = (VIDEO_SCANNER_MAX_VERT - VIDEO_SCANNER_Y_DISPLAY) * VIDEO_SCANNER_MAX_HORZ; g_pFuncUpdateGraphicsScreen( nCyclesVBlank ); + + VideoRefreshScreen(0); } } } From 989522a43d85215f9eaf8269e195282c86035b87 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 12:47:51 -0800 Subject: [PATCH 052/121] Optimization: Add MSVC forced inlining --- source/NTSC.cpp | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 93865ed9..db65daeb 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -36,6 +36,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Defines #define HGR_TEST_PATTERN 0 +#ifdef _MSC_VER + #define INLINE __forceinline +#else + #define INLINE inline +#endif + #define PI 3.1415926535898f #define DEG_TO_RAD(x) (PI*(x)/180.f) // 2PI=360, PI=180,PI/2=90,PI/4=45 #define RAD_45 PI*0.25f @@ -393,24 +399,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // prototypes from Memory.h //unsigned char * MemGetAuxPtr (unsigned short); //unsigned char * MemGetMainPtr (unsigned short); - inline float clampZeroOne( const float & x ); - inline uint8_t getCharSetBits( const int iChar ); - inline uint16_t getLoResBits( uint8_t iByte ); - inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ); - inline uint32_t* getScanlineNext1Address(); - inline uint32_t* getScanlinePrev1Address(); - inline uint32_t* getScanlinePrev2Address(); - inline uint32_t* getScanlineThis0Address(); - inline void updateColorPhase(); - inline void updateFlashRate(); - inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ); - inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ); - inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ); - inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ); - inline void updatePixels( uint16_t bits ); - inline bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self ); - inline void updateVideoScannerHorzEOL(); - inline void updateVideoScannerAddress(); + INLINE float clampZeroOne( const float & x ); + INLINE uint8_t getCharSetBits( const int iChar ); + INLINE uint16_t getLoResBits( uint8_t iByte ); + INLINE uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ); + INLINE uint32_t* getScanlineNext1Address(); + INLINE uint32_t* getScanlinePrev1Address(); + INLINE uint32_t* getScanlinePrev2Address(); + INLINE uint32_t* getScanlineThis0Address(); + INLINE void updateColorPhase(); + INLINE void updateFlashRate(); + INLINE void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable ); + INLINE void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable ); + INLINE void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable ); + INLINE void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable ); + INLINE void updatePixels( uint16_t bits ); + INLINE bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self ); + INLINE void updateVideoScannerHorzEOL(); + INLINE void updateVideoScannerAddress(); static void initChromaPhaseTables(); static real initFilterChroma (real z); From 3c70963d862a54a6e4e9bde68f3ff8345ff13b20 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 13:03:47 -0800 Subject: [PATCH 053/121] WIP: NTSC Full screen support --- source/Frame.cpp | 48 ++++++++++++++++++++---------------------------- source/Video.cpp | 15 +++------------ 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 5b521d09..7ad444cc 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -141,10 +141,9 @@ static int viewporty = VIEWPORTY; // Default to Normal (non-FullScreen int g_nCharsetType = 0; // Direct Draw -- For Full Screen - LPDIRECTDRAW g_pDD = (LPDIRECTDRAW)0; - LPDIRECTDRAWSURFACE g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0; - IDirectDrawPalette* g_pDDPal = (IDirectDrawPalette*)0; - + LPDIRECTDRAW g_pDD = (LPDIRECTDRAW)0; + LPDIRECTDRAWSURFACE g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0; + HDC g_hDDdc = 0; static bool g_bShowingCursor = true; static bool g_bLastCursorInAppleViewport = false; @@ -516,8 +515,6 @@ static void DrawFrameWindow () ? BeginPaint(g_hFrameWindow,&ps) : GetDC(g_hFrameWindow)); - VideoRealizePalette(dc); - if (!g_bIsFullScreen) { // DRAW THE 3D BORDER AROUND THE EMULATED SCREEN @@ -563,7 +560,7 @@ static void DrawFrameWindow () else if (g_nAppMode == MODE_DEBUG) DebugDisplay(1); else - // Win7: In fullscreen mode with 1 redraw, the the screen doesn't get redraw. + // Win7: In fullscreen mode with 1 redraw the screen doesn't get redrawn. //VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) //VideoRefreshScreen(0); VideoRedrawScreen(); @@ -2068,9 +2065,11 @@ void SetFullScreenMode () ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddsd.dwBackBufferCount = 1; + if (DirectDrawCreate(NULL,&g_pDD,NULL) != DD_OK || g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) != DD_OK || - g_pDD->SetDisplayMode(640,480,g_bFullScreen32Bit ? 32 : 8) != DD_OK || + g_pDD->SetDisplayMode(640,480,32) != DD_OK || g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) != DD_OK) { g_pDDPrimarySurface = NULL; @@ -2078,9 +2077,6 @@ void SetFullScreenMode () return; } - // TODO: DD Full-Screen Palette - // if( !g_bIsFullScreen ) - InvalidateRect(g_hFrameWindow,NULL,1); #endif // NO_DIRECT_X @@ -2105,15 +2101,6 @@ void SetNormalMode () framerect.right - framerect.left, framerect.bottom - framerect.top, SWP_NOZORDER | SWP_FRAMECHANGED); - - // DD Full-Screen Palette: BUGFIX: Re-attach new palette on next new surface - // Delete Palette - if (g_pDDPal) - { - g_pDDPal->Release(); - g_pDDPal = (LPDIRECTDRAWPALETTE)0; - } - if (g_pDDPrimarySurface) { g_pDDPrimarySurface->Release(); @@ -2359,6 +2346,8 @@ HDC FrameGetDC () { //=========================================================================== HDC FrameGetVideoDC (LPBYTE *pAddr_, LONG *pPitch_) { + HDC hDC = 0; + // ASSERT( pAddr_ ); // ASSERT( pPitch_ ); if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow) @@ -2374,23 +2363,23 @@ HDC FrameGetVideoDC (LPBYTE *pAddr_, LONG *pPitch_) { g_pDDPrimarySurface->Restore(); g_pDDPrimarySurface->Lock(&rect,&surfacedesc,DDLOCK_WAIT,NULL); - - // DD Full Screen Palette -// if (g_pDDPal) -// { -// g_pDDPrimarySurface->SetPalette(g_pDDPal); // this sets the palette for the primary surface -// } } *pAddr_ = (LPBYTE)surfacedesc.lpSurface + (g_nViewportCY-1) * surfacedesc.lPitch; *pPitch_ = -surfacedesc.lPitch; - return (HDC)0; + + if( g_pDDPrimarySurface->GetDC( &hDC ) == DD_OK ) + g_hDDdc = hDC; // intentional "null" copy + else + hDC = 0; } else { *pAddr_ = g_pFramebufferbits; *pPitch_ = FRAMEBUFFER_W; - return FrameGetDC(); + hDC = FrameGetDC(); } + + return hDC; } //=========================================================================== @@ -2445,6 +2434,9 @@ void FrameReleaseVideoDC () // BUT THIS SEEMS TO BE WORKING g_pDDPrimarySurface->Unlock(NULL); + + g_pDDPrimarySurface->ReleaseDC( g_hDDdc ); // NTSC Full Screen + g_hDDdc = 0; } } diff --git a/source/Video.cpp b/source/Video.cpp index f3105112..cf954276 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1065,16 +1065,6 @@ void VideoDisplayLogo () DeleteObject(font); } -//=========================================================================== -void VideoRealizePalette(HDC dc) -{ - if (g_hPalette) - { - SelectPalette(dc,g_hPalette,0); - RealizePalette(dc); - } -} - //=========================================================================== void VideoRedrawScreen () @@ -1131,7 +1121,7 @@ void VideoRefreshScreen ( int bVideoModeFlags ) NTSC_VideoUpdateCycles( VIDEO_SCANNER_6502_CYCLES ); } -// NTSC_BEGIN: wsVideoRefresh() +// NTSC_BEGIN LPBYTE pDstFrameBufferBits = 0; LONG pitch = 0; HDC hFrameDC = FrameGetVideoDC(&pDstFrameBufferBits,&pitch); @@ -1149,6 +1139,8 @@ void VideoRefreshScreen ( int bVideoModeFlags ) GdiFlush(); } + FrameReleaseVideoDC(); + if (g_VideoForceFullRedraw) --g_VideoForceFullRedraw; // NTSC_END @@ -1761,4 +1753,3 @@ void videoCreateDIBSection() NTSC_VideoInit( g_pFramebufferbits ); } - From 7fcb3763b7717f69f53bee303c6c5b592eb7e7ee Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 14:13:55 -0800 Subject: [PATCH 054/121] WIP Fullscreen support --- source/Frame.cpp | 40 +++++++++++----------------------- source/Frame.h | 3 ++- source/Video.cpp | 56 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 7ad444cc..9e1580f4 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -144,6 +144,8 @@ int g_nCharsetType = 0; LPDIRECTDRAW g_pDD = (LPDIRECTDRAW)0; LPDIRECTDRAWSURFACE g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0; HDC g_hDDdc = 0; + int g_nDDFullScreenW = 640; + int g_nDDFullScreenH = 480; static bool g_bShowingCursor = true; static bool g_bLastCursorInAppleViewport = false; @@ -565,7 +567,6 @@ static void DrawFrameWindow () //VideoRefreshScreen(0); VideoRedrawScreen(); - // DD Full-Screen Palette: BUGFIX: needs to come _after_ all drawing... if (g_bPaintingWindow) EndPaint(g_hFrameWindow,&ps); else @@ -893,9 +894,6 @@ static void EraseButton (int number) { rect.top = buttony+number*BUTTONCY; rect.bottom = rect.top+BUTTONCY; - // TODO: DD Full-Screen Palette - // if( !g_bIsFullScreen ) - InvalidateRect(g_hFrameWindow,&rect,1); } @@ -1476,26 +1474,10 @@ LRESULT CALLBACK FrameWndProc ( // message must not realize its palette, unless it determines that // wParam does not contain its own window handle. if ((HWND)wparam == window) - { -#if DEBUG_DD_PALETTE - if( g_bIsFullScreen ) - OutputDebugString( "WM_PALETTECHANGED: Full Screen\n" ); - else - OutputDebugString( "WM_PALETTECHANGED: Windowed\n" ); -#endif - break; - } + break; // else fall through case WM_QUERYNEWPALETTE: -#if DEBUG_DD_PALETTE - if( g_bIsFullScreen ) - OutputDebugString( "WM_QUERYNEWPALETTE: Full Screen\n" ); - else - OutputDebugString( "WM_QUERYNEWPALETTE: Windowed\n" ); -#endif - - // TODO: DD Full-Screen Palette DrawFrameWindow(); break; @@ -1564,7 +1546,6 @@ LRESULT CALLBACK FrameWndProc ( OutputDebugString( "WM_SYSCOLORCHANGE: Windowed\n" ); #endif - // TODO: DD Full-Screen Palette DeleteGdiObjects(); CreateGdiObjects(); break; @@ -2069,7 +2050,7 @@ void SetFullScreenMode () if (DirectDrawCreate(NULL,&g_pDD,NULL) != DD_OK || g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) != DD_OK || - g_pDD->SetDisplayMode(640,480,32) != DD_OK || + g_pDD->SetDisplayMode(g_nDDFullScreenW,g_nDDFullScreenH,32) != DD_OK || g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) != DD_OK) { g_pDDPrimarySurface = NULL; @@ -2352,10 +2333,15 @@ HDC FrameGetVideoDC (LPBYTE *pAddr_, LONG *pPitch_) // ASSERT( pPitch_ ); if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow) { - RECT rect = { FSVIEWPORTX, - FSVIEWPORTY, - FSVIEWPORTX+g_nViewportCX, - FSVIEWPORTY+g_nViewportCY}; + // Reference: http://archive.gamedev.net/archive/reference/articles/article608.html + // NTSC TODO: Are these coordinates correct?? Coordinates don't seem to matter on Win7 fullscreen!? + // g_nViewportCX = FRAMEBUFFER_W * kDEFAULT_VIEWPORT_SCALE; + RECT rect = { + FSVIEWPORTX, + FSVIEWPORTY, + FSVIEWPORTX+g_nViewportCX, + FSVIEWPORTY+g_nViewportCY + }; DDSURFACEDESC surfacedesc; surfacedesc.dwSize = sizeof(surfacedesc); // TC: Use DDLOCK_WAIT - see Bug #13425 diff --git a/source/Frame.h b/source/Frame.h index 357177c7..81f87278 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -25,7 +25,8 @@ // Direct Draw -- For Full Screen extern LPDIRECTDRAW g_pDD; extern LPDIRECTDRAWSURFACE g_pDDPrimarySurface; - extern IDirectDrawPalette* g_pDDPal; + extern int g_nDDFullScreenW; + extern int g_nDDFullScreenH; // Win32 extern HWND g_hFrameWindow; diff --git a/source/Video.cpp b/source/Video.cpp index cf954276..94aef201 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -885,8 +885,8 @@ BYTE VideoCheckVbl ( ULONG uExecutedCycles ) { bool bVblBar = VideoGetVbl(uExecutedCycles); // NTSC: It is tempting to replace with - // bool bVblBar = NTSC_VideoIsVbl(); - // But this breaks "ANSI STORY" + // bool bVblBar = NTSC_VideoIsVbl(); + // But this breaks "ANSI STORY" intro center fade BYTE r = KeybGetKeycode(); return (r & ~0x80) | (bVblBar ? 0x80 : 0); @@ -1006,10 +1006,11 @@ void VideoDisplayLogo () } // DRAW THE VERSION NUMBER + TCHAR sFontName[] = TEXT("Arial"); HFONT font = CreateFont(-20,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, VARIABLE_PITCH | 4 | FF_SWISS, - TEXT("Arial")); + sFontName ); SelectObject(hFrameDC,font); SetTextAlign(hFrameDC,TA_RIGHT | TA_TOP); SetBkMode(hFrameDC,TRANSPARENT); @@ -1043,19 +1044,35 @@ void VideoDisplayLogo () // NTSC Alpha Version DeleteObject(font); +/* font = CreateFontA( -48,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, VARIABLE_PITCH | 4 | FF_SWISS, - TEXT("Arial") + sFontName) ); +*/ + PLOGFONT pLogFont = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT)); + int angle = 33 * 10; // 3600 = 360 degrees + pLogFont->lfHeight = -48; + pLogFont->lfWeight = FW_NORMAL; + pLogFont->lfEscapement = angle; + pLogFont->lfOrientation = angle; + SetTextAlign(hFrameDC,TA_BASELINE); + + font = CreateFontIndirect( pLogFont ); + HGDIOBJ hFontPrev = SelectObject(hFrameDC, font); + SelectObject(hFrameDC,font); - sprintf( szVersion, "NTSC Alpha v12 AnsiStory" ); - xoff = 0; - yoff = 0; - DRAWVERSION( 42, -158*scale,RGB(0x00,0x00,0x00)); - DRAWVERSION( 41, -157*scale,RGB(0x00,0x00,0x00)); - DRAWVERSION( 40, -156*scale,RGB(0xFF,0x00,0xFF)); + sprintf( szVersion, "NTSC Alpha v13 FullScreen" ); + xoff = -nViewportCX + nViewportCX/6; + yoff = +nViewportCY/16; + DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); + DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); + DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); + + LocalFree((LOCALHANDLE)pLogFont); + SelectObject(hFrameDC,hFontPrev); // NTSC END #undef DRAWVERSION @@ -1126,15 +1143,26 @@ void VideoRefreshScreen ( int bVideoModeFlags ) LONG pitch = 0; HDC hFrameDC = FrameGetVideoDC(&pDstFrameBufferBits,&pitch); +#if 1 // Keep Aspect Ratio + // Need to clear full screen logo to black + #define W g_nViewportCX + #define H g_nViewportCY +#else // Stretch + // Stretch - doesn't preserve 1:1 aspect ratio + #define W g_bIsFullScreen ? g_nDDFullScreenW : g_nViewportCX + #define H g_bIsFullScreen ? g_nDDFullScreenH : g_nViewportCY +#endif + if (hFrameDC) { StretchBlt( hFrameDC, - 0,0, - g_nViewportCX,g_nViewportCY, //dst + 0, 0, + W, // dst + H, // dst g_hDeviceDC, - 0,0, - FRAMEBUFFER_W,FRAMEBUFFER_H, // src + 0, 0, + FRAMEBUFFER_W, FRAMEBUFFER_H, // src // NOT 560, 384 SRCCOPY ); GdiFlush(); } From 3eec694262a47eaf3afadc14fcb324d40600557f Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 18:22:51 -0800 Subject: [PATCH 055/121] Doc: Made note about duplicate NTSC constants! --- source/Common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Common.h b/source/Common.h index dc549637..f89db922 100644 --- a/source/Common.h +++ b/source/Common.h @@ -8,6 +8,7 @@ const double CLK_6502 = ((_M14 * 65.0) / 912.0); // 65 cycles per 912 14M clocks // See: http://www.apple2info.net/hardware/softcard/SC-SWHW_a2in.pdf const double CLK_Z80 = (CLK_6502 * 2); +// TODO: Clean up from Common.h, Video.cpp, and NTSC.h !!! const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL' const UINT uVisibleLinesPerFrame = 64*3; // 192 const UINT uLinesPerFrame = 262; // 64 in each third of the screen & 70 in VBL From 898a82cded7a1f6ec76aa79f872a7a602cb5f195 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 18:28:47 -0800 Subject: [PATCH 056/121] Replace NTSC_VideoGetByte() with NTSC_VideoGetScannerAddress() --- source/NTSC.cpp | 7 ++++--- source/NTSC.h | 17 ++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index db65daeb..495be1f7 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1529,10 +1529,11 @@ _mono: } //=========================================================================== -uint8_t NTSC_VideoGetByte (unsigned long cycles6502) +uint16_t NTSC_VideoGetScannerAddress ( unsigned long cycles6502 ) { - uint8_t *pMain = MemGetMainPtr( g_aHorzClockMemAddress[ g_nVideoClockHorz ] ); - return pMain[0]; + (void)cycles6502; // TODO: Do we need to offset based on the clock cycles? + // uint8_t h = (g_nVideoClockHorz + cycles6502) % VIDEO_SCANNER_MAX_HORZ + return g_aHorzClockMemAddress[ g_nVideoClockHorz ]; } //=========================================================================== diff --git a/source/NTSC.h b/source/NTSC.h index 5b98d53d..4a050284 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -6,13 +6,12 @@ extern uint16_t g_nVideoClockHorz; // Prototypes (Public) ________________________________________________ - extern void NTSC_SetVideoTextMode( int cols ); - extern void NTSC_SetVideoMode( int flags ); - extern void NTSC_SetVideoStyle(); - - extern uint8_t NTSC_VideoGetByte(unsigned long); - extern void NTSC_VideoInit( uint8_t *pFramebuffer ); - extern void NTSC_VideoInitAppleType (); - extern bool NTSC_VideoIsVbl(); - extern void NTSC_VideoUpdateCycles( long cycles ); + extern void NTSC_SetVideoMode( int bVideoModeFlags ); + extern void NTSC_SetVideoStyle(); + extern void NTSC_SetVideoTextMode( int cols ); + extern uint16_t NTSC_VideoGetScannerAddress( unsigned long cycles6502 ); + extern void NTSC_VideoInit( uint8_t *pFramebuffer ); + extern void NTSC_VideoInitAppleType (); + extern bool NTSC_VideoIsVbl(); + extern void NTSC_VideoUpdateCycles( long cycles6502 ); From b74aa9ed87c17d88e2df5bd5f607fab8708334b2 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 18:32:34 -0800 Subject: [PATCH 057/121] Cleanup: macros UpdateVideoAddressTXT() -> updateVideoScannerAddressTXT, UpdateVideoAddressHGR() -> updateVideoScannerAddressHGR() --- source/NTSC.cpp | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 495be1f7..16f4275b 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -162,9 +162,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned g_aPixelMaskGR [ 16]; static uint16_t g_aPixelDoubleMaskHGR[128]; // hgrbits -> g_aPixelDoubleMaskHGR: 7-bit mono 280 pixels to 560 pixel doubling -#define UpdateVideoAddressTXT() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] + g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400)) -#define UpdateVideoAddressHGR() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)) // BUG? g_pHorzClockOffset - static int g_nLastColumnPixelNTSC; static int g_nColorBurstPixels; @@ -768,6 +765,22 @@ inline void updateVideoScannerAddress() g_aFuncUpdateHorz[0] = g_pFuncUpdateGraphicsScreen; } +//=========================================================================== +INLINE uint16_t updateVideoScannerAddressTXT() +{ + return g_aHorzClockMemAddress[ g_nVideoClockHorz ] = (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] + + g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400)); +} + +//=========================================================================== +INLINE uint16_t updateVideoScannerAddressHGR() +{ + // BUG? g_pHorzClockOffset + return g_aHorzClockMemAddress[ g_nVideoClockHorz ] = (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)); +} + + // Non-Inline _________________________________________________________ // Build the 4 phase chroma lookup table @@ -1061,8 +1074,6 @@ static void updatePixelHueMonitorDoubleScanline (uint16_t compositeSignal) //=========================================================================== void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 { - unsigned ad; - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { g_pFuncUpdateTextScreen( cycles6502 ); @@ -1071,7 +1082,7 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressHGR(); + uint16_t addr = updateVideoScannerAddressHGR(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1083,7 +1094,7 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 { if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleHires40 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); uint8_t m = pMain[0]; uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 updatePixels( bits ); @@ -1096,7 +1107,6 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 //=========================================================================== void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires { - unsigned ad; uint16_t bits; if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) @@ -1107,7 +1117,7 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressHGR(); + uint16_t addr = updateVideoScannerAddressHGR(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1119,8 +1129,8 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires { if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleHires80 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t *pAux = MemGetAuxPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); + uint8_t *pAux = MemGetAuxPtr (addr); uint8_t m = pMain[0]; uint8_t a = pAux [0]; @@ -1138,8 +1148,6 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires //=========================================================================== void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores { - unsigned ad; - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { g_pFuncUpdateTextScreen( cycles6502 ); @@ -1148,7 +1156,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressTXT(); + uint16_t addr = updateVideoScannerAddressTXT(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1160,7 +1168,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores { if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleLores40 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); uint8_t m = pMain[0]; uint16_t lo = getLoResBits( m ); uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits @@ -1174,8 +1182,6 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores //=========================================================================== void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores { - unsigned ad; - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { g_pFuncUpdateTextScreen( cycles6502 ); @@ -1184,7 +1190,7 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressTXT(); + uint16_t addr = updateVideoScannerAddressTXT(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1196,8 +1202,8 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores { if( updateScanLineModeSwitch( cycles6502, updateScreenDoubleLores80 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); - uint8_t *pAux = MemGetAuxPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); + uint8_t *pAux = MemGetAuxPtr (addr); uint8_t m = pMain[0]; uint8_t a = pAux [0]; @@ -1221,8 +1227,6 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores //=========================================================================== void updateScreenSingleHires40 (long cycles6502) { - unsigned ad; - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { g_pFuncUpdateTextScreen( cycles6502 ); @@ -1231,7 +1235,7 @@ void updateScreenSingleHires40 (long cycles6502) for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressHGR(); + uint16_t addr = updateVideoScannerAddressHGR(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1243,7 +1247,7 @@ void updateScreenSingleHires40 (long cycles6502) { if ( updateScanLineModeSwitch( cycles6502, updateScreenSingleHires40 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); uint8_t m = pMain[0]; uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 if (m & 0x80) @@ -1258,8 +1262,6 @@ void updateScreenSingleHires40 (long cycles6502) //=========================================================================== void updateScreenSingleLores40 (long cycles6502) { - unsigned ad; - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { g_pFuncUpdateTextScreen( cycles6502 ); @@ -1268,7 +1270,7 @@ void updateScreenSingleLores40 (long cycles6502) for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressTXT(); + uint16_t addr = updateVideoScannerAddressTXT(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1280,7 +1282,7 @@ void updateScreenSingleLores40 (long cycles6502) { if( updateScanLineModeSwitch( cycles6502, updateScreenSingleLores40 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); uint8_t m = pMain[0]; uint16_t lo = getLoResBits( m ); uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2); @@ -1294,11 +1296,9 @@ void updateScreenSingleLores40 (long cycles6502) //=========================================================================== void updateScreenText40 (long cycles6502) { - unsigned ad; - for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressTXT(); + uint16_t addr = updateVideoScannerAddressTXT(); if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) { @@ -1311,7 +1311,7 @@ void updateScreenText40 (long cycles6502) { if ( updateScanLineModeSwitch( cycles6502, updateScreenText40 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); uint8_t m = pMain[0]; uint8_t c = getCharSetBits(m); uint16_t bits = g_aPixelDoubleMaskHGR[c & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128 @@ -1330,11 +1330,9 @@ void updateScreenText40 (long cycles6502) //=========================================================================== void updateScreenText80 (long cycles6502) { - unsigned int ad; - for (; cycles6502 > 0; --cycles6502) { - UpdateVideoAddressTXT(); + uint16_t addr = updateVideoScannerAddressTXT(); if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) { @@ -1347,8 +1345,8 @@ void updateScreenText80 (long cycles6502) { if ( updateScanLineModeSwitch( cycles6502, updateScreenText80 ) ) return; // ANSI STORY: vide mode switch mid scan line! - uint8_t *pAux = MemGetAuxPtr(ad); - uint8_t *pMain = MemGetMainPtr(ad); + uint8_t *pMain = MemGetMainPtr(addr); + uint8_t *pAux = MemGetAuxPtr (addr); uint8_t m = pMain[0]; uint8_t a = pAux [0]; From cb57b3a9db759d278890915cb1650cd5119979cb Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 18:34:09 -0800 Subject: [PATCH 058/121] Added debug code for VideoScannerAddress() --- source/Memory.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 05ae1d9a..1451efb7 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1478,15 +1478,20 @@ void MemResetPaging() BYTE MemReadFloatingBus(const ULONG uExecutedCycles) { +#if 0 // NTSC: It is tempting to replace with - // return NTSC_VideoGetByte( uExecutedCycles ); + // return NTSC_VideoGetByte( uExecutedCycles ); // But that breaks "Rainbow" Bug #254 - // Why is this out of sync?? - //uint8_t val1 = NTSC_VideoGetByte( uExecutedCycles ); - //uint8_t val2 = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); - //if( val1 != val2 ) mem[ 0x2000 ] ^= 0xFF; + // Why is this out of sync?? + uint16_t a1 = NTSC_VideoGetScannerAddressByte( uExecutedCycles ); + uint16_t a2 = VideoGetScannerAddress(NULL, uExecutedCycles); + uint8_t b1 = mem[ a1 ]; + uint8_t b2 = mem[ a2 ]; - return *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); + if( val1 != val2 ) + mem[ 0x2000 ] ^= 0xFF; +#endif + return mem[ VideoGetScannerAddress(NULL, uExecutedCycles) ]; } //=========================================================================== From 201515771c01a9e2e50bc0d45cd287475c1e6374 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 3 Jan 2015 18:36:16 -0800 Subject: [PATCH 059/121] Added missing prototype --- source/NTSC.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 16f4275b..e693c4b1 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -414,6 +414,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA INLINE bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self ); INLINE void updateVideoScannerHorzEOL(); INLINE void updateVideoScannerAddress(); + INLINE uint16_t updateVideoScannerAddressTXT(); + INLINE uint16_t updateVideoScannerAddressHGR(); static void initChromaPhaseTables(); static real initFilterChroma (real z); From 7c468af8d1a801f6301d7c6f036036e509691d8c Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sun, 4 Jan 2015 01:10:30 -0800 Subject: [PATCH 060/121] Massive cleanup for filters --- source/NTSC.cpp | 127 ++++++++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 52 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index e693c4b1..4c5137d8 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -184,22 +184,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static bgra_t g_aBnWMonitorCustom [NTSC_NUM_SEQUENCES]; static bgra_t g_aBnWColorTVCustom [NTSC_NUM_SEQUENCES]; - #define NUM_SIGZEROS 2 - #define NUM_SIGPOLES 2 - #define SIGGAIN 7.614490548f + #define CHROMA_ZEROS 2 + #define CHROMA_POLES 2 + #define CHROMA_GAIN 7.438011255f // Should this be 7.15909 MHz ? + #define CHROMA_0 -0.7318893645f + #define CHROMA_1 1.2336442711f - #define NUM_LUMZEROS 2 - #define NUM_LUMPOLES 2 //#define LUMGAIN 1.062635655e+01 //#define LUMCOEF1 -0.3412038399 //#define LUMCOEF2 0.9647813115 - #define LUMGAIN 13.71331570f - #define LUMCOEF1 -0.3961075449f - #define LUMCOEF2 1.1044202472f + #define LUMA_ZEROS 2 + #define LUMA_POLES 2 + #define LUMA_GAIN 13.71331570f // Should this be 14.318180 MHz ? + #define LUMA_0 -0.3961075449f + #define LUMA_1 1.1044202472f + + #define SIGNAL_ZEROS 2 + #define SIGNAL_POLES 2 + #define SIGNAL_GAIN 7.614490548f // Should this be 7.15909 MHz ? + #define SIGNAL_0 -0.2718798058f + #define SIGNAL_1 0.7465656072f - #define NUM_CHRZEROS 2 - #define NUM_CHRPOLES 2 - #define CHRGAIN 7.438011255f // Tables static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] = @@ -487,7 +492,6 @@ inline uint32_t* getScanlinePrev1Address() inline uint32_t* getScanlinePrev2Address() { return (uint32_t*) (g_pVideoAddress + 2*FRAMEBUFFER_W); - } //=========================================================================== @@ -533,6 +537,7 @@ inline void updateFlashRate() // TODO: Flash rate should be constant (regardless g_pVideoAddress++; \ } while(0) +// prevp is never used nor blended with! #define updateFramebufferColorTVSingleScanline(signal,table) \ do { \ uint32_t ntscp, prevp, betwp; \ @@ -583,7 +588,7 @@ inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTa const uint32_t color0 = getScanlineColor( signal, pTable ); const uint32_t color2 = *pLine2Address; - const uint32_t color1 = color0 - ((color0 & 0x00fcfcfc) >> 2); + const uint32_t color1 = color0 - ((color2 & 0x00fcfcfc) >> 2); // BUG? color0 - color0? not color0-color2? /* */ *pLine1Address = color1 | ALPHA32_MASK; /* */ *pLine0Address = color0; @@ -815,9 +820,9 @@ static void initChromaPhaseTables (void) #if CHROMA_BLUR //z = z * 1.25; zz = initFilterSignal(z); - c = initFilterChroma(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees - y0 = initFilterLuma0(zz); - y1 = initFilterLuma1(zz - c); + c = initFilterChroma(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees + y0 = initFilterLuma0 (zz); + y1 = initFilterLuma1 (zz - c); #else // CHROMA_BLUR y0 = y0 + (z - y0) / 4.0; y1 = y0; // fix TV mode @@ -918,68 +923,86 @@ static void initChromaPhaseTables (void) } } +/* +http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html +Sample Rate: ??? +Corner Freq 1: ? +Corner Freq 2: ? + +double ButterworthLowPass2( double a, double b, double g, double z ) +{ + const int POLES=2; + static double x[POLES+1]; + static double y[POLES+1]; + + for( int iPole = 0; iPole < POLES; iPole++ ) + { + x[iPole] = x[iPole+1]; + y[iPole] = y[iPole+1]; + } + + x[POLES] = z / g; + y[POLES] = x[0] + x[2] + (2.f*x[1]) + (a*y[0]) + (b*y[1]); + + return y[2]; +} + +*/ + +// What filter is this ?? +// Filter Order: 2 -> poles for low pass //=========================================================================== static real initFilterChroma (real z) { - static real xv[NUM_CHRZEROS + 1] = {0,0,0}; - static real yv[NUM_CHRPOLES + 1] = {0,0,0}; + static real x[CHROMA_ZEROS + 1] = {0,0,0}; + static real y[CHROMA_POLES + 1] = {0,0,0}; - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / CHRGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[2] - xv[0] + (-0.7318893645f * yv[0]) + (1.2336442711f * yv[1]); + x[0] = x[1]; x[1] = x[2]; x[2] = z / CHROMA_GAIN; + y[0] = y[1]; y[1] = y[2]; y[2] = x[2] - x[0] + (CHROMA_0*y[0]) + (CHROMA_1*y[1]); - return yv[2]; + return y[2]; } +// Butterworth Lowpass digital filter +// Filter Order: 2 -> poles for low pass //=========================================================================== static real initFilterLuma0 (real z) { - static real xv[NUM_LUMZEROS + 1] = { 0,0,0 }; - static real yv[NUM_LUMPOLES + 1] = { 0,0,0 }; + static real x[LUMA_ZEROS + 1] = { 0,0,0 }; + static real y[LUMA_POLES + 1] = { 0,0,0 }; - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / LUMGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); + x[0] = x[1]; x[1] = x[2]; x[2] = z / LUMA_GAIN; + y[0] = y[1]; y[1] = y[2]; y[2] = x[0] + x[2] + (2.f*x[1]) + (LUMA_0*y[0]) + (LUMA_1*y[1]); - return yv[2]; + return y[2]; } +// Butterworth Lowpass digital filter +// Filter Order: 2 -> poles for low pass //=========================================================================== static real initFilterLuma1 (real z) { - static real xv[NUM_LUMZEROS + 1] = { 0,0,0}; - static real yv[NUM_LUMPOLES + 1] = { 0,0,0}; + static real x[LUMA_ZEROS + 1] = { 0,0,0}; + static real y[LUMA_POLES + 1] = { 0,0,0}; - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / LUMGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[0] + xv[2] + (2 * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]); + x[0] = x[1]; x[1] = x[2]; x[2] = z / LUMA_GAIN; + y[0] = y[1]; y[1] = y[2]; y[2] = x[0] + x[2] + (2.f*x[1]) + (LUMA_0*y[0]) + (LUMA_1*y[1]); - return yv[2]; + return y[2]; } +// Butterworth Lowpass digital filter +// Filter Order: 2 -> poles for low pass //=========================================================================== static real initFilterSignal (real z) { - static real xv[NUM_SIGZEROS + 1] = { 0,0,0 }; - static real yv[NUM_SIGPOLES + 1] = { 0,0,0 }; + static real x[SIGNAL_ZEROS + 1] = { 0,0,0 }; + static real y[SIGNAL_POLES + 1] = { 0,0,0 }; - xv[0] = xv[1]; - xv[1] = xv[2]; - xv[2] = z / SIGGAIN; - yv[0] = yv[1]; - yv[1] = yv[2]; - yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (-0.2718798058f * yv[0]) + (0.7465656072f * yv[1]); + x[0] = x[1]; x[1] = x[2]; x[2] = z / SIGNAL_GAIN; + y[0] = y[1]; y[1] = y[2]; y[2] = x[0] + x[2] + (2.f*x[1]) + (SIGNAL_0*y[0]) + (SIGNAL_1*y[1]); - return yv[2]; + return y[2]; } //=========================================================================== From 1d06cd0a3fbc983a53c5f0635e3feb1c6adaff9c Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sun, 4 Jan 2015 02:03:54 -0800 Subject: [PATCH 061/121] Tweak colors to be 12 degrees offset --- source/NTSC.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 4c5137d8..5ef3f202 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -61,7 +61,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #if CHROMA_BLUR //#define CYCLESTART (PI/4.f) // PI/4 = 45 degrees - #define CYCLESTART (DEG_TO_RAD(45)) + #define CYCLESTART (DEG_TO_RAD(33)) #else // sharpness is higher, less color bleed #if CHROMA_FILTER == 2 #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = initFilterSignal(z); @@ -205,7 +205,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SIGNAL_0 -0.2718798058f #define SIGNAL_1 0.7465656072f - // Tables static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] = { @@ -958,7 +957,7 @@ static real initFilterChroma (real z) static real y[CHROMA_POLES + 1] = {0,0,0}; x[0] = x[1]; x[1] = x[2]; x[2] = z / CHROMA_GAIN; - y[0] = y[1]; y[1] = y[2]; y[2] = x[2] - x[0] + (CHROMA_0*y[0]) + (CHROMA_1*y[1]); + y[0] = y[1]; y[1] = y[2]; y[2] = -x[0] + x[2] + (CHROMA_0*y[0]) + (CHROMA_1*y[1]); // inverted x[0] return y[2]; } From 05eb35e418744a35bbc5dc16a9c5c5e94c6c3086 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Mon, 5 Jan 2015 08:39:29 -0800 Subject: [PATCH 062/121] Bug #241 Fixed ANSI STORY Video Scanner Vertical --- source/Memory.cpp | 25 +++++++++++++++---------- source/NTSC.cpp | 22 +++++++++++++++------- source/Video.cpp | 14 +++++++++----- source/Video.h | 3 ++- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 1451efb7..56c36b00 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1480,18 +1480,23 @@ BYTE MemReadFloatingBus(const ULONG uExecutedCycles) { #if 0 // NTSC: It is tempting to replace with - // return NTSC_VideoGetByte( uExecutedCycles ); - // But that breaks "Rainbow" Bug #254 - // Why is this out of sync?? - uint16_t a1 = NTSC_VideoGetScannerAddressByte( uExecutedCycles ); - uint16_t a2 = VideoGetScannerAddress(NULL, uExecutedCycles); - uint8_t b1 = mem[ a1 ]; - uint8_t b2 = mem[ a2 ]; + // return NTSC_VideoGetScannerAddress( uExecutedCycles ); + // But that breaks "Rainbow" Bug #254 if NTSC_VideoGetScannerAddress() is not correct. + // This is out of sync with VideoGetScannerAddress() due to two reasons: + // a) returning a cached copy of g_aHorzClockMemAddress + // Fixed by calling: updateVideoScannerAddressTXT or updateVideoScannerAddressHGR() + // b) A bug? in APPLE_IIE_HORZ_CLOCK_OFFSET[0][8] containing the incorrect value of 0x006F + uint16_t addr1 = NTSC_VideoGetScannerAddress( uExecutedCycles ); + uint16_t addr2 = VideoGetScannerAddress(NULL, uExecutedCycles); + uint8_t byte1 = mem[ addr1 ]; + uint8_t byte2 = mem[ addr2 ]; - if( val1 != val2 ) + if( byte1 != byte2 ) mem[ 0x2000 ] ^= 0xFF; #endif - return mem[ VideoGetScannerAddress(NULL, uExecutedCycles) ]; + // return mem[ VideoGetScannerAddress(NULL, uExecutedCycles) ]; + uint16_t addr = NTSC_VideoGetScannerAddress( uExecutedCycles ); + return mem[ addr ] ; // cycles is ignored } //=========================================================================== @@ -1499,7 +1504,7 @@ BYTE MemReadFloatingBus(const ULONG uExecutedCycles) BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles) { // NTSC: It is tempting to replace with - // return NTSC_VideoGetByte( uExecutedCycles ); + // return NTSC_VideoGetScannerAddress( uExecutedCycles ); // But that breaks "Rainbow" Bug #254 // BYTE r= NTSC_VideoGetByte( uExecutedCycles ); BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 5ef3f202..daeb4dda 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -291,7 +291,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = { - {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x106F, // bug? 0x106F + {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, // bug? 0x106F 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, @@ -746,7 +746,7 @@ inline void updateVideoScannerHorzEOL() g_nVideoClockVert = 0; updateFlashRate(); - //VideoRefreshScreen(0); // ContinueExecution() calls VideoRefreshScreen(0) ever dwClksPerFrame (17030) + //VideoRefreshScreen(0); // ContinueExecution() calls VideoRefreshScreen(0) every dwClksPerFrame (17030) } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) @@ -1392,7 +1392,7 @@ void updateScreenText80 (long cycles6502) } } -// Functions (Public) _________________________________________________ +// Functions (Public) _____________________________________________________________________________ //=========================================================================== void NTSC_SetVideoTextMode( int cols ) @@ -1407,7 +1407,6 @@ void NTSC_SetVideoTextMode( int cols ) void NTSC_SetVideoMode( int bVideoModeFlags ) { int h = g_nVideoClockHorz; -// int h = (g_dwCyclesThisFrame + 40) % 65; g_aHorzClockVideoMode[ h ] = bVideoModeFlags; @@ -1417,6 +1416,8 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) g_nTextPage = 1; g_nHiresPage = 1; if (bVideoModeFlags & VF_PAGE2) { + // Apple IIe, Techical Nodtes, #3: Double High-Resolution Graphics + // 80STORE must be OFF to display page 2 if (0 == (bVideoModeFlags & VF_80STORE)) { g_nTextPage = 2; g_nHiresPage = 2; @@ -1553,9 +1554,16 @@ _mono: //=========================================================================== uint16_t NTSC_VideoGetScannerAddress ( unsigned long cycles6502 ) { - (void)cycles6502; // TODO: Do we need to offset based on the clock cycles? - // uint8_t h = (g_nVideoClockHorz + cycles6502) % VIDEO_SCANNER_MAX_HORZ - return g_aHorzClockMemAddress[ g_nVideoClockHorz ]; + (void)cycles6502; + + int nHires = (g_uVideoMode & VF_HIRES) && !(g_uVideoMode & VF_TEXT); // (SW_HIRES && !SW_TEXT) ? 1 : 0; + if( nHires ) + updateVideoScannerAddressHGR(); + else + updateVideoScannerAddressTXT(); + + // Required for ANSI STORY vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80 + return g_aHorzClockMemAddress[ (g_nVideoClockHorz+VIDEO_SCANNER_MAX_HORZ-2)%VIDEO_SCANNER_MAX_HORZ ]; // Optimization: (h-2) } //=========================================================================== diff --git a/source/Video.cpp b/source/Video.cpp index 94aef201..52aa8366 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -255,7 +255,7 @@ COLORREF g_nMonochromeRGB = RGB(0xC0,0xC0,0xC0); static BOOL rebuiltsource = 0; static LPBYTE vidlastmem = NULL; -static UINT g_uVideoMode = VF_TEXT; + uint32_t g_uVideoMode = VF_TEXT; // Current Video Mode (this is the last set one as it may change mid-scan line!) DWORD g_eVideoType = VT_COLOR_TVEMU; DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look @@ -1196,8 +1196,9 @@ void VideoResetState () BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) { address &= 0xFF; - DWORD oldpage2 = SW_PAGE2; - int oldvalue = g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2)); + +// DWORD oldpage2 = SW_PAGE2; +// int oldvalue = g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2)); switch (address) { @@ -1219,13 +1220,16 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break; } + // Apple IIe, Techical Nodtes, #3: Double High-Resolution Graphics + // 80STORE must be OFF to display page 2 + if (SW_80STORE) + g_uVideoMode &= ~VF_PAGE2; + // NTSC_BEGIN NTSC_SetVideoMode( g_uVideoMode ); // NTSC_END #if 0 // NTSC_CLEANUP: Is this still needed?? - if (SW_80STORE) - g_uVideoMode &= ~VF_PAGE2; if (oldvalue != g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2))) g_VideoForceFullRedraw = 1; // Defer video redraw until VideoEndOfVideoFrame() diff --git a/source/Video.h b/source/Video.h index 090b9cad..142e4314 100644 --- a/source/Video.h +++ b/source/Video.h @@ -58,7 +58,8 @@ extern HBITMAP g_hLogoBitmap; extern COLORREF g_nMonochromeRGB; // saved -extern DWORD g_eVideoType; // saved +extern uint32_t g_uVideoMode ; +extern DWORD g_eVideoType ; // saved extern DWORD g_uHalfScanLines; // saved extern uint8_t *g_pFramebufferbits; extern int g_nAltCharSetOffset; // alternate character set From 5b266a51fb611213729de08e48c7caa70876cb13 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Mon, 5 Jan 2015 22:03:09 -0800 Subject: [PATCH 063/121] 1.26alpha v14 FullScreen --- source/Video.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Video.cpp b/source/Video.cpp index 52aa8366..590f6ac5 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1064,7 +1064,7 @@ void VideoDisplayLogo () HGDIOBJ hFontPrev = SelectObject(hFrameDC, font); SelectObject(hFrameDC,font); - sprintf( szVersion, "NTSC Alpha v13 FullScreen" ); + sprintf( szVersion, "NTSC Alpha v14 HorzClock" ); xoff = -nViewportCX + nViewportCX/6; yoff = +nViewportCY/16; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); From c9741ae1336a6920e8393a08652b8e081bb0e85a Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Mon, 5 Jan 2015 22:03:49 -0800 Subject: [PATCH 064/121] optimize removal white ringing, touch up HGR test pattern --- source/NTSC.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index daeb4dda..87f243e3 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -891,11 +891,7 @@ static void initChromaPhaseTables (void) // Remove white ringing if(brightness > 0.9f) - { - b64 += 0.25; - g64 += 0.25; - r64 += 0.25; - } + b64 = g64 = r64 = 1.0; b32 = clampZeroOne( (float)b64); g32 = clampZeroOne( (float)g64); @@ -1585,15 +1581,16 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit VideoReinitialize(); // Setup g_pFunc_ntsc*Pixel() #if HGR_TEST_PATTERN -// Michael -- Init HGR to almost all-possible-combinations +// Init HGR to almost all-possible-combinations // CALL-151 // C050 C053 C057 unsigned char b = 0; unsigned char *main, *aux; + uint16_t ad; for( unsigned page = 0; page < 2; page++ ) { - for( unsigned w = 0; w < 2; w++ ) // 16 cols +// for( unsigned w = 0; w < 2; w++ ) // 16 cols { for( unsigned z = 0; z < 2; z++ ) // 8 cols { @@ -1603,19 +1600,30 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit for( unsigned y = 0; y < 64; y++ ) // 1 col { unsigned y2 = y*2; - ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; + ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z; // + 20*w; ad += 0x2000*page; main = MemGetMainPtr(ad); aux = MemGetAuxPtr (ad); - main[0] = b; main[1] = w + page*0x80; + main[0] = b; main[1] = z + page*0x80; aux [0] = z; aux [1] = 0; + if( page == 1 ) + { + // Columns = # of consecutive pixels + // x = 0, 1, 2, 3 + // # = 3, 5, 7, 9 + // b = 3, 7, 15, 31 + // = (4 << x) - 1 + main[0+z] = (0x80*(y/32) + (((4 << x) - 1) << (y/8))); // (3 | 3+x*2) + main[1+z] = (0x80*(y/32) + (((4 << x) - 1) << (y/8))) >> 8; + } + y2 = y*2 + 1; - ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w; + ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z; // + 20*w; ad += 0x2000*page; main = MemGetMainPtr(ad); aux = MemGetAuxPtr (ad); - main[0] = 0; main[1] = w + page*0x80; + main[0] = 0; main[1] = z + page*0x80; aux [0] = b; aux [1] = 0; b++; From d56751773e0c5c094139de15c99124095200f217 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Mon, 5 Jan 2015 22:55:36 -0800 Subject: [PATCH 065/121] Cleanup NTSC_VideoGetScannerAddress() --- source/NTSC.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 87f243e3..63754dbf 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1558,8 +1558,9 @@ uint16_t NTSC_VideoGetScannerAddress ( unsigned long cycles6502 ) else updateVideoScannerAddressTXT(); - // Required for ANSI STORY vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80 - return g_aHorzClockMemAddress[ (g_nVideoClockHorz+VIDEO_SCANNER_MAX_HORZ-2)%VIDEO_SCANNER_MAX_HORZ ]; // Optimization: (h-2) + // Required for ANSI STORY vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80 + uint8_t hclock = (g_nVideoClockHorz + VIDEO_SCANNER_MAX_HORZ - 2) % VIDEO_SCANNER_MAX_HORZ; // Optimization: (h-2) + return g_aHorzClockMemAddress[ hclock ]; } //=========================================================================== From ad6215dbc7851cdfde77d28c51cd8246cb21368f Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Mon, 5 Jan 2015 22:58:35 -0800 Subject: [PATCH 066/121] Fix DX to page flip in full screen; this allows Fraps to capture the screen --- source/Frame.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 9e1580f4..8bbd0783 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -55,6 +55,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Configuration\PropertySheet.h" #include "Debugger\Debug.h" +#define DIRECTX_PAGE_FLIP 1 + //#define ENABLE_MENU 0 // Magic numbers (used by FrameCreateWindow to calc width/height): @@ -143,6 +145,9 @@ int g_nCharsetType = 0; // Direct Draw -- For Full Screen LPDIRECTDRAW g_pDD = (LPDIRECTDRAW)0; LPDIRECTDRAWSURFACE g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0; +#if DIRECTX_PAGE_FLIP + LPDIRECTDRAWSURFACE g_pDDBackSurface = (LPDIRECTDRAWSURFACE)0; +#endif HDC g_hDDdc = 0; int g_nDDFullScreenW = 640; int g_nDDFullScreenH = 480; @@ -2044,14 +2049,22 @@ void SetFullScreenMode () DDSURFACEDESC ddsd; ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; - if (DirectDrawCreate(NULL,&g_pDD,NULL) != DD_OK || - g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) != DD_OK || - g_pDD->SetDisplayMode(g_nDDFullScreenW,g_nDDFullScreenH,32) != DD_OK || - g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) != DD_OK) + DDSCAPS ddscaps; + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + + if ( 0 + || DD_OK != DirectDrawCreate(NULL,&g_pDD,NULL) + || DD_OK != g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) + || DD_OK != g_pDD->SetDisplayMode(g_nDDFullScreenW,g_nDDFullScreenH,32) + || DD_OK != g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) +#if DIRECTX_PAGE_FLIP + || DD_OK != g_pDDPrimarySurface->GetAttachedSurface( &ddscaps, &g_pDDBackSurface) +#endif + ) { g_pDDPrimarySurface = NULL; SetNormalMode(); @@ -2416,6 +2429,12 @@ void FrameReleaseVideoDC () FSVIEWPORTX+g_nViewportCX, FSVIEWPORTY+g_nViewportCY }; + + //g_pDDBackSurface->BltFast( 0, 0, g_pDDPrimarySurface, &rcRect,DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT); +#if DIRECTX_PAGE_FLIP + g_pDDBackSurface->Flip( g_pDDPrimarySurface, 0 ); +#endif + g_pDDPrimarySurface->Unlock(&rect); // BUT THIS SEEMS TO BE WORKING From 00f9d8f1b914da037dfa26ae005f3871bc648498 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Mon, 5 Jan 2015 23:14:44 -0800 Subject: [PATCH 067/121] Cleanup dead code --- source/NTSC.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 63754dbf..1f956b71 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1420,8 +1420,6 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) } } - UpdateScreenFunc_t pPrevUpdate = g_pFuncUpdateGraphicsScreen; - if (bVideoModeFlags & VF_TEXT) { if (bVideoModeFlags & VF_80COL) g_pFuncUpdateGraphicsScreen = updateScreenText80; @@ -1446,16 +1444,8 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) else g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40; } -#if 0 - g_aFuncUpdateHorz[ g_nVideoClockHorz ] = g_pFuncUpdateGraphicsScreen; // ANSI STORY - if( g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START ) - g_pFuncUpdateGraphicsScreen = pPrevUpdate; - else - g_aFuncUpdateHorz[0] = g_pFuncUpdateGraphicsScreen; -#else g_aFuncUpdateHorz[ h ] = g_pFuncUpdateGraphicsScreen; // NTSC: ANSI STORY -#endif } //=========================================================================== From 8809caefe2920621012c6c25e727c111cfc1d77e Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Tue, 6 Jan 2015 01:45:38 -0800 Subject: [PATCH 068/121] Added new logo, fixed fullscreen y offset --- ApplewinExpress10.00.vcxproj | 1 + resource/Applewin.rc | 2 +- resource/ApplewinLogo.bmp | Bin 0 -> 645174 bytes source/Video.cpp | 16 +++++++++++----- 4 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 resource/ApplewinLogo.bmp diff --git a/ApplewinExpress10.00.vcxproj b/ApplewinExpress10.00.vcxproj index 48c2bca6..eb54c1df 100644 --- a/ApplewinExpress10.00.vcxproj +++ b/ApplewinExpress10.00.vcxproj @@ -462,6 +462,7 @@ + diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 52038c89..34ada1c9 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -73,7 +73,7 @@ CHARSET8M BITMAP "CHARSET8C.BMP" CHARSET8C BITMAP "CHARSET8C.BMP" HELP_BUTTON BITMAP "HELP.BMP" DRIVESWAP_BUTTON BITMAP "DRIVESWAP.BMP" -IDB_APPLEWIN BITMAP "Applewin.bmp" +IDB_APPLEWIN BITMAP "ApplewinLogo.bmp" IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp" ///////////////////////////////////////////////////////////////////////////// diff --git a/resource/ApplewinLogo.bmp b/resource/ApplewinLogo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e81f68a22af4b3c8513d99b9c50330cc68ad0034 GIT binary patch literal 645174 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%0Dhn1(T>qw7S`0 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�J6K*`X??Ea|4(-|#`bi0sLfFq&X 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 bm.bmHeight) yoff = (nViewportCY - (scale * bm.bmHeight)) / 2; + if( g_bIsFullScreen ) + { + yoff = 0; + } + VideoDrawLogoBitmap( hFrameDC, xoff, yoff, bm.bmWidth, bm.bmHeight, scale ); } } @@ -1078,7 +1084,7 @@ void VideoDisplayLogo () #undef DRAWVERSION FrameReleaseDC(); - DeleteObject(brush); +// DeleteObject(brush); DeleteObject(font); } From aa119833fab6ad9512861bf394f21d29f7a0819c Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Tue, 6 Jan 2015 13:19:43 -0800 Subject: [PATCH 069/121] Added GIMP source converted from PSD --- assets/ApplewinLogo.xcf | Bin 0 -> 444244 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/ApplewinLogo.xcf diff --git a/assets/ApplewinLogo.xcf b/assets/ApplewinLogo.xcf new file mode 100644 index 0000000000000000000000000000000000000000..91c1d4277a8180ad110395f27d5c622f63c8765c GIT binary patch literal 444244 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

^P3l9-bCkvf^6 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

o+hS#jEryQj(J;m9L^ScUy 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 literal 0 HcmV?d00001 From a1d730a0b993f9497040bb6e2eb559fd2a452e16 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 7 Jan 2015 00:46:37 -0800 Subject: [PATCH 070/121] Bump version to 1.26 Alpha --- resource/Applewin.rc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 34ada1c9..172da881 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -249,8 +249,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,25,0,3 - PRODUCTVERSION 1,25,0,3 + FILEVERSION 1,26,0,0 + PRODUCTVERSION 1,26,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -268,12 +268,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 25, 0, 3" + VALUE "FileVersion", "1.26.0.0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2014 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis" VALUE "OriginalFilename", "APPLEWIN.EXE" VALUE "ProductName", "Apple //e Emulator" - VALUE "ProductVersion", "1, 25, 0, 3" + VALUE "ProductVersion", "1.26.0.0 Alpha" END END BLOCK "VarFileInfo" From 5dc58980696858e6dbc0678b899482c8644bcf10 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 7 Jan 2015 00:48:18 -0800 Subject: [PATCH 071/121] Display the logo in for the first few initial frames so any full screen video captures can get it --- source/Video.cpp | 81 ++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index 19e278e1..c7728b25 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -969,45 +969,37 @@ void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int DeleteObject( hSrcDC ); } +int g_nLogoWidth = FRAMEBUFFER_W; +int g_nLogoX = 0; +int g_nLogoY = 0; + //=========================================================================== void VideoDisplayLogo () { - int xoff = 0, yoff = 0, scale = 0; + int xoff = 0, yoff = 0; + const int scale = GetViewportScale(); + HDC hFrameDC = FrameGetDC(); // DRAW THE LOGO -// HBRUSH brush = CreateSolidBrush(PALETTERGB(0x70,0x30,0xE0)); -// SelectObject(hFrameDC, brush); - SelectObject(hFrameDC, GetStockObject(NULL_PEN)); - int nViewportCX, nViewportCY; - GetViewportCXCY(nViewportCX, nViewportCY); - Rectangle(hFrameDC, 0, 0, nViewportCX+1, nViewportCY+1); - if (g_hLogoBitmap) { BITMAP bm; if (GetObject(g_hLogoBitmap, sizeof(bm), &bm)) { - scale = nViewportCX / bm.bmWidth; - if (nViewportCY / bm.bmHeight < scale) - scale = nViewportCY / bm.bmHeight; + g_nLogoWidth = bm.bmWidth; + g_nLogoX = (g_nViewportCX - scale*g_nLogoWidth)/2; + g_nLogoY = (g_nViewportCY - scale*bm.bmHeight )/2; - if (scale > 0) + // Draw Logo at top of screen so when the Apple display is refreshed it will automagically clear it + if( g_bIsFullScreen ) { - if (nViewportCX > bm.bmWidth) - xoff = (nViewportCX - (scale * bm.bmWidth)) / 2; - if (nViewportCY > bm.bmHeight) - yoff = (nViewportCY - (scale * bm.bmHeight)) / 2; - - if( g_bIsFullScreen ) - { - yoff = 0; - } - - VideoDrawLogoBitmap( hFrameDC, xoff, yoff, bm.bmWidth, bm.bmHeight, scale ); + g_nLogoX = 10; + g_nLogoY = 0; } + VideoDrawLogoBitmap( hFrameDC, g_nLogoX, g_nLogoY, bm.bmWidth, bm.bmHeight, scale ); } } @@ -1059,7 +1051,7 @@ void VideoDisplayLogo () ); */ PLOGFONT pLogFont = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT)); - int angle = 33 * 10; // 3600 = 360 degrees + int angle = 7.5 * 10; // 3600 = 360 degrees pLogFont->lfHeight = -48; pLogFont->lfWeight = FW_NORMAL; pLogFont->lfEscapement = angle; @@ -1067,12 +1059,13 @@ void VideoDisplayLogo () SetTextAlign(hFrameDC,TA_BASELINE); font = CreateFontIndirect( pLogFont ); - HGDIOBJ hFontPrev = SelectObject(hFrameDC, font); + HGDIOBJ hFontPrev = SelectObject(hFrameDC, font); SelectObject(hFrameDC,font); - sprintf( szVersion, "NTSC Alpha v14 HorzClock" ); - xoff = -nViewportCX + nViewportCX/6; - yoff = +nViewportCY/16; +// sprintf( szVersion, "NTSC Alpha v14 HorzClock" ); + sprintf( szVersion, "NTSC Alpha v15 Fraps" ); + xoff = -g_nViewportCX + g_nViewportCX/6; + yoff = +g_nViewportCY/16; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); @@ -1083,8 +1076,8 @@ void VideoDisplayLogo () #undef DRAWVERSION - FrameReleaseDC(); -// DeleteObject(brush); + FrameReleaseVideoDC(); + DeleteObject(font); } @@ -1161,17 +1154,25 @@ void VideoRefreshScreen ( int bVideoModeFlags ) if (hFrameDC) { - StretchBlt( - hFrameDC, - 0, 0, - W, // dst - H, // dst - g_hDeviceDC, - 0, 0, - FRAMEBUFFER_W, FRAMEBUFFER_H, // src // NOT 560, 384 - SRCCOPY ); - GdiFlush(); + // Display the logo for a second so that any full screen screen-caps will have it + static int nLogo = 30; // HACK + if ((nLogo > 0) && nLogo-- ) + { + int nScale = g_bIsFullScreen ? 1 : GetViewportScale(); + VideoDrawLogoBitmap( hFrameDC, g_nLogoX, g_nLogoY, 560, 384, nScale ); + } + else + StretchBlt( + hFrameDC, + 0, 0, + W, // dst + H, // dst + g_hDeviceDC, + 0, 0, + FRAMEBUFFER_W, FRAMEBUFFER_H, // src // NOT 560, 384 + SRCCOPY ); } + GdiFlush(); FrameReleaseVideoDC(); From 897d72b03f29511203d08396104dc26974387128 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 7 Jan 2015 19:01:43 -0800 Subject: [PATCH 072/121] Cleanup up warning --- source/Video.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Video.cpp b/source/Video.cpp index c7728b25..6ccb0770 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1051,7 +1051,7 @@ void VideoDisplayLogo () ); */ PLOGFONT pLogFont = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT)); - int angle = 7.5 * 10; // 3600 = 360 degrees + int angle = (int)(7.5 * 10); // 3600 = 360 degrees pLogFont->lfHeight = -48; pLogFont->lfWeight = FW_NORMAL; pLogFont->lfEscapement = angle; From 1fb2e412fdc54bb4b30e14d0e56a8ecb7791a0bb Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Wed, 7 Jan 2015 19:03:06 -0800 Subject: [PATCH 073/121] The mother of all debugger cleanups --- source/Debugger/Debugger_Commands.cpp | 764 +++++++++++++------------- 1 file changed, 384 insertions(+), 380 deletions(-) diff --git a/source/Debugger/Debugger_Commands.cpp b/source/Debugger/Debugger_Commands.cpp index 72fe701d..84840c81 100644 --- a/source/Debugger/Debugger_Commands.cpp +++ b/source/Debugger/Debugger_Commands.cpp @@ -40,341 +40,344 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Command_t g_aCommands[] = { // Assembler - {TEXT("A") , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" }, +// {"!" , CmdAssemberMini , CMD_ASSEMBLER_MINI , "Mini assembler" } + {"A" , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" } // CPU (Main) - {TEXT(".") , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" }, // centered - {TEXT("=") , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" }, - {TEXT("G") , CmdGo , CMD_GO , "Run [until PC = address]" }, - {TEXT("IN") , CmdIn , CMD_IN , "Input byte from IO $C0xx" }, - {TEXT("KEY") , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" }, - {TEXT("JSR") , CmdJSR , CMD_JSR , "Call sub-routine" }, - {TEXT("NOP") , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" }, - {TEXT("OUT") , CmdOut , CMD_OUT , "Output byte to IO $C0xx" }, + ,{"." , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" } // centered + ,{"=" , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" } +// ,{"g" , CmdGoNormalSpeed , CMD_GO_NORMAL , "Run @ normal speed [until PC == address]" } +// ,{"G" , CmdGoFullSpeed , CMD_GO_FULL , "Run @ full speed [until PC == address]" } + ,{"G" , CmdGo , CMD_GO , "Run @ full speed [until PC == address]" } + ,{"IN" , CmdIn , CMD_IN , "Input byte from IO $C0xx" } + ,{"KEY" , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" } + ,{"JSR" , CmdJSR , CMD_JSR , "Call sub-routine" } + ,{"NOP" , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" } + ,{"OUT" , CmdOut , CMD_OUT , "Output byte to IO $C0xx" } // CPU - Meta Info - {TEXT("PROFILE") , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" }, - {TEXT("R") , CmdRegisterSet , CMD_REGISTER_SET , "Set register" }, + ,{"PROFILE" , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" } + ,{"R" , CmdRegisterSet , CMD_REGISTER_SET , "Set register" } // CPU - Stack - {TEXT("POP") , CmdStackPop , CMD_STACK_POP }, - {TEXT("PPOP") , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO }, - {TEXT("PUSH") , CmdStackPop , CMD_STACK_PUSH }, -// {TEXT("RTS") , CmdStackReturn , CMD_STACK_RETURN }, - {TEXT("P") , CmdStepOver , CMD_STEP_OVER , "Step current instruction" }, - {TEXT("RTS") , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" }, + ,{"POP" , CmdStackPop , CMD_STACK_POP } + ,{"PPOP" , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO } + ,{"PUSH" , CmdStackPop , CMD_STACK_PUSH } +// ,{"RTS" , CmdStackReturn , CMD_STACK_RETURN } + ,{"P" , CmdStepOver , CMD_STEP_OVER , "Step current instruction" } + ,{"RTS" , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" } // CPU - Meta Info - {TEXT("T") , CmdTrace , CMD_TRACE , "Trace current instruction" }, - {TEXT("TF") , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" }, - {TEXT("TL") , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" }, - {TEXT("U") , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" }, -// {TEXT("WAIT") , CmdWait , CMD_WAIT , "Run until + ,{"T" , CmdTrace , CMD_TRACE , "Trace current instruction" } + ,{"TF" , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" } + ,{"TL" , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" } + ,{"U" , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" } +// ,{"WAIT" , CmdWait , CMD_WAIT , "Run until" // Bookmarks - {TEXT("BM") , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" }, - {TEXT("BMA") , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" }, - {TEXT("BMC") , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" }, - {TEXT("BML") , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" }, - {TEXT("BMG") , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" }, -// {TEXT("BMLOAD") , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" }, - {TEXT("BMSAVE") , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" }, + ,{"BM" , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" } + ,{"BMA" , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" } + ,{"BMC" , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" } + ,{"BML" , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" } + ,{"BMG" , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" } +// ,{"BMLOAD" , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" } + ,{"BMSAVE" , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" } // Breakpoints - {TEXT("BRK") , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" }, - {TEXT("BRKOP") , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" }, - {TEXT("BP") , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" }, - {TEXT("BPA") , CmdBreakpointAddSmart, CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" }, -// {TEXT("BPP") , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" }, - {TEXT("BPR") , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" }, // NOTE! Different from SoftICE !!!! - {TEXT("BPX") , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" }, - {TEXT("BPIO") , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" }, - {TEXT("BPM") , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" }, // SoftICE + ,{"BRK" , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" } + ,{"BRKOP" , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" } + ,{"BP" , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" } + ,{"BPA" , CmdBreakpointAddSmart , CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" } +// ,{"BPP" , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" } + ,{"BPR" , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" } // NOTE! Different from SoftICE !!!! + ,{"BPX" , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" } + ,{"BPIO" , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" } + ,{"BPM" , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" } // SoftICE - {TEXT("BPC") , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" }, // SoftICE - {TEXT("BPD") , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" }, // SoftICE - {TEXT("BPEDIT") , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" }, // SoftICE - {TEXT("BPE") , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" }, // SoftICE - {TEXT("BPL") , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" }, // SoftICE -// {TEXT("BPLOAD") , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" }, - {TEXT("BPSAVE") , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" }, + ,{"BPC" , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" } // SoftICE + ,{"BPD" , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" } // SoftICE + ,{"BPEDIT" , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" } // SoftICE + ,{"BPE" , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" } // SoftICE + ,{"BPL" , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" } // SoftICE +// ,{"BPLOAD" , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" } + ,{"BPSAVE" , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" } // Config - {TEXT("BENCHMARK") , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" }, - {TEXT("BW") , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" }, - {TEXT("COLOR") , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" }, -// {TEXT("OPTION") , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" }, - {TEXT("DISASM") , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." }, - {TEXT("FONT") , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" }, - {TEXT("HCOLOR") , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" }, - {TEXT("LOAD") , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" }, - {TEXT("MONO") , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" }, - {TEXT("SAVE") , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" }, - {TEXT("PWD") , CmdConfigGetDebugDir , CMD_CONFIG_GET_DEBUG_DIR , "Displays the current debugger directory. Used for scripts & mem load/save." }, - {TEXT("CD") , CmdConfigSetDebugDir , CMD_CONFIG_SET_DEBUG_DIR , "Updates the current debugger directory." }, + ,{"BENCHMARK" , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" } + ,{"BW" , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" } + ,{"COLOR" , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" } +// ,{"OPTION" , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" } + ,{"DISASM" , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." } + ,{"FONT" , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" } + ,{"HCOLOR" , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" } + ,{"LOAD" , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" } + ,{"MONO" , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" } + ,{"SAVE" , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" } + ,{"PWD" , CmdConfigGetDebugDir , CMD_CONFIG_GET_DEBUG_DIR , "Display current debugger directory for scripts & mem load/save." } + ,{"CD" , CmdConfigSetDebugDir , CMD_CONFIG_SET_DEBUG_DIR , "Update current debugger directory." } // Cursor - {TEXT("RET") , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the sub-routine caller" }, - {TEXT( "^") , NULL , CMD_CURSOR_LINE_UP }, // \x2191 = Up Arrow (Unicode) - {TEXT("Shift ^") , NULL , CMD_CURSOR_LINE_UP_1 }, - {TEXT( "v") , NULL , CMD_CURSOR_LINE_DOWN }, // \x2193 = Dn Arrow (Unicode) - {TEXT("Shift v") , NULL , CMD_CURSOR_LINE_DOWN_1 }, - {TEXT("PAGEUP" ) , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" }, - {TEXT("PAGEUP256") , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" }, // Shift - {TEXT("PAGEUP4K" ) , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" }, // Ctrl - {TEXT("PAGEDN" ) , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" }, - {TEXT("PAGEDOWN256") , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" }, // Shift - {TEXT("PAGEDOWN4K" ) , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" }, // Ctrl + ,{"RET" , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the subroutine caller" } + ,{ "^" , NULL , CMD_CURSOR_LINE_UP } // \x2191 = Up Arrow (Unicode) + ,{"Shift ^" , NULL , CMD_CURSOR_LINE_UP_1 } + ,{ "v" , NULL , CMD_CURSOR_LINE_DOWN } // \x2193 = Dn Arrow (Unicode) + ,{"Shift v" , NULL , CMD_CURSOR_LINE_DOWN_1 } + ,{"PAGEUP" , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" } + ,{"PAGEUP256" , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" } // Shift + ,{"PAGEUP4K" , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" } // Ctrl + ,{"PAGEDN" , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" } + ,{"PAGEDOWN256" , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" } // Shift + ,{"PAGEDOWN4K" , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" } // Ctrl // Disassembler Data - {TEXT("Z") , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" }, - {TEXT("X") , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" }, + ,{"Z" , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" } + ,{"X" , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" } // TODO: Conflicts with monitor command #L -> 000DL - {TEXT("B") , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" }, + ,{"B" , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" } // without symbol lookup - {TEXT("DB") , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1, "Define byte(s)" }, - {TEXT("DB2") , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2, "Define byte array, display 2 bytes/line" }, - {TEXT("DB4") , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4, "Define byte array, display 4 bytes/line" }, - {TEXT("DB8") , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8, "Define byte array, display 8 bytes/line" }, - {TEXT("DW") , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1, "Define address array" }, - {TEXT("DW2") , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2, "Define address array, display 2 words/line" }, - {TEXT("DW4") , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4, "Define address array, display 4 words/line" }, - {TEXT("ASC") , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define text string" }, // 2.7.0.26 Changed: DS to ASC because DS is used as "Define Space" assembler directive -// {TEXT("DF") , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT, "Define AppleSoft (packed) Float" }, -// {TEXT("DFX") , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2,"Define AppleSoft (unpacked) Float" }, + ,{"DB" , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1 , "Define byte(s)" } + ,{"DB2" , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2 , "Define byte array, display 2 bytes/line" } + ,{"DB4" , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4 , "Define byte array, display 4 bytes/line" } + ,{"DB8" , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8 , "Define byte array, display 8 bytes/line" } + ,{"DW" , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1 , "Define address array" } + ,{"DW2" , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2 , "Define address array, display 2 words/line" } + ,{"DW4" , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4 , "Define address array, display 4 words/line" } + ,{"ASC" , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define text string" } // 2.7.0.26 Changed: DS to ASC because DS is used as "Define Space" assembler directive +// .{"DF" , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT , "Define AppleSoft (packed) Float" } +// .{"DFX" , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2 , "Define AppleSoft (unpacked) Float" } // with symbol lookup -// {TEXT("DA<>") , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" }, -// {TEXT("DA><") , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" }, -// {TEXT("DA<") , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" }, -// {TEXT("DB>") , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } - {TEXT("DA") , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" }, +// .{"DA<>" , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" } +// .{"DA><" , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" } +// .{"DA<" , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" } +// .{"DB>" , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } + ,{"DA" , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" } // TODO: Rename config cmd: DISASM -// {TEXT("UA") , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE, "Analyze opcodes to determine if code or data" }, +// {"UA" , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE , "Analyze opcodes to determine if code or data" } // Disk - {TEXT("DISK") , CmdDisk , CMD_DISK , "Access Disk Drive Functions" }, + ,{"DISK" , CmdDisk , CMD_DISK , "Access Disk Drive Functions" } // Flags -// {TEXT("FC") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* +// {"FC" , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" } // NVRBDIZC see AW_CPU.cpp AF_* // TODO: Conflicts with monitor command #L -> 000CL - {TEXT("CL") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* + ,{"CL" , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" } // NVRBDIZC see AW_CPU.cpp AF_* - {TEXT("CLC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy - {TEXT("CLZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 - {TEXT("CLI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 - {TEXT("CLD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 - {TEXT("CLB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy - {TEXT("CLR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 - {TEXT("CLV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 - {TEXT("CLN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 + ,{"CLC" , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" } // 0 // Legacy + ,{"CLZ" , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" } // 1 + ,{"CLI" , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" } // 2 + ,{"CLD" , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" } // 3 + ,{"CLB" , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" } // 4 // Legacy + ,{"CLR" , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" } // 5 + ,{"CLV" , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" } // 6 + ,{"CLN" , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" } // 7 -// {TEXT("FS") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, - {TEXT("SE") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, +// ,{"FS" , CmdFlag , CMD_FLAG_SET , "Set specified Flag" } + ,{"SE" , CmdFlag , CMD_FLAG_SET , "Set specified Flag" } - {TEXT("SEC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 - {TEXT("SEZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 - {TEXT("SEI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 - {TEXT("SED") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 - {TEXT("SEB") , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" }, // 4 // Legacy - {TEXT("SER") , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" }, // 5 - {TEXT("SEV") , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" }, // 6 - {TEXT("SEN") , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" }, // 7 + ,{"SEC" , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" } // 0 + ,{"SEZ" , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" } // 1 + ,{"SEI" , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" } // 2 + ,{"SED" , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" } // 3 + ,{"SEB" , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" } // 4 // Legacy + ,{"SER" , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" } // 5 + ,{"SEV" , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" } // 6 + ,{"SEN" , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" } // 7 // Help - {TEXT("?") , CmdHelpList , CMD_HELP_LIST , "List all available commands" }, - {TEXT("HELP") , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" }, - {TEXT("VERSION") , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" }, - {TEXT("MOTD") , CmdMOTD , CMD_MOTD }, // MOTD: Message Of The Day + ,{"?" , CmdHelpList , CMD_HELP_LIST , "List all available commands" } + ,{"HELP" , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" } + ,{"VERSION" , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" } + ,{"MOTD" , CmdMOTD , CMD_MOTD } // MOTD: Message Of The Day // Memory - {TEXT("MC") , CmdMemoryCompare , CMD_MEMORY_COMPARE }, + ,{"MC" , CmdMemoryCompare , CMD_MEMORY_COMPARE } - {TEXT("MD1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, - {TEXT("MD2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" }, + ,{"MD1" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" } + ,{"MD2" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" } - {TEXT("MA1") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_1, "ASCII text in mini memory area 1" }, - {TEXT("MA2") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_2, "ASCII text in mini memory area 2" }, - {TEXT("MT1") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_1, "Apple Text in mini memory area 1" }, - {TEXT("MT2") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_2, "Apple Text in mini memory area 2" }, -// {TEXT("ML1") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1, "Text (Ctrl) in mini memory dump area 1" }, -// {TEXT("ML2") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2, "Text (Ctrl) in mini memory dump area 2" }, -// {TEXT("MH1") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_1, "Text (High) in mini memory dump area 1" }, -// {TEXT("MH2") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_2, "Text (High) in mini memory dump area 2" }, + ,{"MA1" , CmdMemoryMiniDumpAscii , CMD_MEM_MINI_DUMP_ASCII_1 , "ASCII text in mini memory area 1" } + ,{"MA2" , CmdMemoryMiniDumpAscii , CMD_MEM_MINI_DUMP_ASCII_2 , "ASCII text in mini memory area 2" } + ,{"MT1" , CmdMemoryMiniDumpApple , CMD_MEM_MINI_DUMP_APPLE_1 , "Apple Text in mini memory area 1" } + ,{"MT2" , CmdMemoryMiniDumpApple , CMD_MEM_MINI_DUMP_APPLE_2 , "Apple Text in mini memory area 2" } +// {"ML1" , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1 , "Text (Ctrl) in mini memory dump area 1" } +// {"ML2" , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2 , "Text (Ctrl) in mini memory dump area 2" } +// {"MH1" , CmdMemoryMiniDumpHigh , CMD_MEM_MINI_DUMP_TXT_HI_1 , "Text (High) in mini memory dump area 1" } +// {"MH2" , CmdMemoryMiniDumpHigh , CMD_MEM_MINI_DUMP_TXT_HI_2 , "Text (High) in mini memory dump area 2" } - {TEXT("ME") , CmdMemoryEdit , CMD_MEMORY_EDIT , "Memory Editor - Not Implemented!" }, // TODO: like Copy ][+ Sector Edit - {TEXT("MEB") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" }, - {TEXT("MEW") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" }, - {TEXT("BLOAD") , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" }, - {TEXT("M") , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" }, - {TEXT("BSAVE") , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" }, - {TEXT("S") , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" }, - {TEXT("@") ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" }, -// {TEXT("SA") , CmdMemorySearchAscii, CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" }, -// {TEXT("ST") , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" }, - {TEXT("SH") , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" }, - {TEXT("F") , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" }, + ,{"ME" , CmdMemoryEdit , CMD_MEMORY_EDIT , "Memory Editor - Not Implemented!" } // TODO: like Copy ][+ Sector Edit + ,{"MEB" , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" } + ,{"MEW" , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" } + ,{"BLOAD" , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" } + ,{"M" , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" } + ,{"BSAVE" , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" } + ,{"S" , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" } + ,{"@" ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" } +// ,{"SA" , CmdMemorySearchAscii , CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" } +// ,{"ST" , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" } + ,{"SH" , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" } + ,{"F" , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" } - {TEXT("TSAVE") , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" }, + ,{"TSAVE" , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" } // Output / Scripts - {TEXT("CALC") , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" }, - {TEXT("ECHO") , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" }, // or toggle command echoing" - {TEXT("PRINT") , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" }, - {TEXT("PRINTF") , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" }, - {TEXT("RUN") , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" }, + ,{"CALC" , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" } + ,{"ECHO" , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" } // or toggle command echoing" + ,{"PRINT" , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" } + ,{"PRINTF" , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" } + ,{"RUN" , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" } // Source Level Debugging - {TEXT("SOURCE") , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" }, - {TEXT("SYNC") , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" }, + ,{"SOURCE" , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" } + ,{"SYNC" , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" } // Symbols - {TEXT("SYM") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" }, + ,{"SYM" , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" } - {"SYMMAIN" , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMBASIC" , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMASM" , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMUSER" , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMUSER2" , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMSRC" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMSRC2" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMDOS33" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 , "DOS 3.3 symbol table lookup/menu" }, // CLEAR,LOAD,SAVE - {"SYMPRODOS" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS , "ProDOS symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + ,{"SYMMAIN" , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMBASIC" , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMASM" , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMUSER" , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMUSER2" , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMSRC" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMSRC2" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMDOS33" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 , "DOS 3.3 symbol table lookup/menu" } // CLEAR,LOAD,SAVE + ,{"SYMPRODOS" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS , "ProDOS symbol table lookup/menu" } // CLEAR,LOAD,SAVE -// {TEXT("SYMCLEAR") , CmdSymbolsClear , CMD_SYMBOLS_CLEAR }, // can't use SC = SetCarry - {TEXT("SYMINFO") , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" }, - {TEXT("SYMLIST") , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" }, // 'symbolname', can't use param '*' +// ,{"SYMCLEAR" , CmdSymbolsClear , CMD_SYMBOLS_CLEAR } // can't use SC = SetCarry + ,{"SYMINFO" , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" } + ,{"SYMLIST" , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" } // 'symbolname', can't use param '*' // Variables -// {TEXT("CLEAR") , CmdVarsClear , CMD_VARIABLES_CLEAR }, -// {TEXT("VAR") , CmdVarsDefine , CMD_VARIABLES_DEFINE }, -// {TEXT("INT8") , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8}, -// {TEXT("INT16") , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16}, -// {TEXT("VARS") , CmdVarsList , CMD_VARIABLES_LIST }, -// {TEXT("VARSLOAD") , CmdVarsLoad , CMD_VARIABLES_LOAD }, -// {TEXT("VARSSAVE") , CmdVarsSave , CMD_VARIABLES_SAVE }, -// {TEXT("SET") , CmdVarsSet , CMD_VARIABLES_SET }, +// ,{"CLEAR" , CmdVarsClear , CMD_VARIABLES_CLEAR } +// ,{"VAR" , CmdVarsDefine , CMD_VARIABLES_DEFINE } +// ,{"INT8" , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8 } +// ,{"INT16" , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16 } +// ,{"VARS" , CmdVarsList , CMD_VARIABLES_LIST } +// ,{"VARSLOAD" , CmdVarsLoad , CMD_VARIABLES_LOAD } +// ,{"VARSSAVE" , CmdVarsSave , CMD_VARIABLES_SAVE } +// ,{"SET" , CmdVarsSet , CMD_VARIABLES_SET } // View - {TEXT("TEXT") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X, "View Text screen (current page)" }, - {TEXT("TEXT1") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41, "View Text screen Page 1" }, - {TEXT("TEXT2") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42, "View Text screen Page 2" }, - {TEXT("TEXT80") , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X, "View 80-col Text screen (current page)" }, - {TEXT("TEXT81") , CmdViewOutput_Text81 , CMD_VIEW_TEXT81, "View 80-col Text screen Page 1" }, - {TEXT("TEXT82") , CmdViewOutput_Text82 , CMD_VIEW_TEXT82, "View 80-col Text screen Page 2" }, - {TEXT("GR") , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" }, - {TEXT("GR1") , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" }, - {TEXT("GR2") , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" }, - {TEXT("DGR") , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" }, - {TEXT("DGR1") , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" }, - {TEXT("DGR2") , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" }, - {TEXT("HGR") , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" }, - {TEXT("HGR1") , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" }, - {TEXT("HGR2") , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" }, - {TEXT("DHGR") , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" }, - {TEXT("DHGR1") , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" }, - {TEXT("DHGR2") , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" }, + ,{"TEXT" , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X , "View Text screen (current page)" } + ,{"TEXT1" , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 , "View Text screen Page 1" } + ,{"TEXT2" , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 , "View Text screen Page 2" } + ,{"TEXT80" , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X , "View 80-col Text screen (current page)" } + ,{"TEXT81" , CmdViewOutput_Text81 , CMD_VIEW_TEXT81 , "View 80-col Text screen Page 1" } + ,{"TEXT82" , CmdViewOutput_Text82 , CMD_VIEW_TEXT82 , "View 80-col Text screen Page 2" } + ,{"GR" , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" } + ,{"GR1" , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" } + ,{"GR2" , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" } + ,{"DGR" , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" } + ,{"DGR1" , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" } + ,{"DGR2" , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" } + ,{"HGR" , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" } + ,{"HGR1" , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" } + ,{"HGR2" , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" } + ,{"DHGR" , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" } + ,{"DHGR1" , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" } + ,{"DHGR2" , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" } // Watch - {TEXT("W") , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" }, - {TEXT("WA") , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" }, - {TEXT("WC") , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" }, - {TEXT("WD") , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - it is still in the list, just not active" }, - {TEXT("WE") , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" }, - {TEXT("WL") , CmdWatchList , CMD_WATCH_LIST , "List all watches" }, -// {TEXT("WLOAD") , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" }, // Cant use as param to W - {TEXT("WSAVE") , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" }, // due to symbol look-up + ,{"W" , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" } + ,{"WA" , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" } + ,{"WC" , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" } + ,{"WD" , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - listed not active" } + ,{"WE" , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" } + ,{"WL" , CmdWatchList , CMD_WATCH_LIST , "List all watches" } +// ,{"WLOAD" , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" } // Cant use as param to W + ,{"WSAVE" , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" } // due to symbol look-up // Window - {TEXT("WIN") , CmdWindow , CMD_WINDOW , "Show specified debugger window" }, + ,{"WIN" , CmdWindow , CMD_WINDOW , "Show specified debugger window" } // CODE 0, CODE 1, CODE 2 ... ??? - {TEXT("CODE") , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" }, // Can't use WC = WatchClear - {TEXT("CODE1") , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" }, - {TEXT("CODE2") , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" }, - {TEXT("CONSOLE") , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" }, - {TEXT("DATA") , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" }, - {TEXT("DATA1") , CmdWindowShowData1 , CMD_WINDOW_DATA_1 , "Show data on top split window" }, - {TEXT("DATA2") , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" }, - {TEXT("SOURCE1") , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1, "Show source on top split screen" }, - {TEXT("SOURCE2") , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2, "Show source on bottom split screen" }, + ,{"CODE" , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" } // Can't use WC = WatchClear + ,{"CODE1" , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" } + ,{"CODE2" , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" } + ,{"CONSOLE" , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" } + ,{"DATA" , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" } + ,{"DATA1" , CmdWindowShowData1 , CMD_WINDOW_DATA_1 , "Show data on top split window" } + ,{"DATA2" , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" } + ,{"SOURCE1" , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1 , "Show source on top split screen" } + ,{"SOURCE2" , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2 , "Show source on bottom split screen" } - {TEXT("\\") , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" }, -// {TEXT("INFO") , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE }, -// {TEXT("WINSOURCE") , CmdWindowShowSource , CMD_WINDOW_SOURCE }, -// {TEXT("ZEROPAGE") , CmdWindowShowZeropage, CMD_WINDOW_ZEROPAGE }, + ,{"\\" , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" } +// ,{"INFO" , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE } +// ,{"WINSOURCE" , CmdWindowShowSource , CMD_WINDOW_SOURCE } +// ,{"ZEROPAGE" , CmdWindowShowZeropage , CMD_WINDOW_ZEROPAGE } // Zero Page - {TEXT("ZP") , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" }, - {TEXT("ZP0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " }, - {TEXT("ZP1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" }, - {TEXT("ZP2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" }, - {TEXT("ZP3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" }, - {TEXT("ZP4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" }, - {TEXT("ZP5") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " }, - {TEXT("ZP6") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" }, - {TEXT("ZP7") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" }, - {TEXT("ZPA") , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer"}, - {TEXT("ZPC") , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" }, - {TEXT("ZPD") , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE,"Disable zero page pointer - it is still in the list, just not active" }, - {TEXT("ZPE") , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE, "(Re)Enable disabled zero page pointer" }, - {TEXT("ZPL") , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" }, -// {TEXT("ZPLOAD") , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" }, // Cant use as param to ZP - {TEXT("ZPSAVE") , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" }, // due to symbol look-up + ,{"ZP" , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" } + ,{"ZP0" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " } + ,{"ZP1" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" } + ,{"ZP2" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" } + ,{"ZP3" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" } + ,{"ZP4" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" } + ,{"ZP5" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " } + ,{"ZP6" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" } + ,{"ZP7" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" } + ,{"ZPA" , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer" } + ,{"ZPC" , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" } + ,{"ZPD" , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE, "Disable zero page pointer" } + ,{"ZPE" , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE , "(Re)Enable disabled zero page pointer" } + ,{"ZPL" , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" } +// ,{"ZPLOAD" , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" } // Cant use as param to ZP + ,{"ZPSAVE" , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" } // due to symbol look-up -// {TEXT("TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() -// {TEXT("WC"),CmdShowCodeWindow}, // Can't use since WatchClear -// {TEXT("WD"),CmdShowDataWindow}, // +// {"TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() +// {"WC"),CmdShowCodeWindow}, // Can't use since WatchClear +// {"WD"),CmdShowDataWindow}, // // Internal Consistency Check - { DEBUGGER__COMMANDS_VERIFY_TXT__, NULL, NUM_COMMANDS }, + ,{ DEBUGGER__COMMANDS_VERIFY_TXT__, NULL, NUM_COMMANDS } // Aliasies - Can be in any order - {TEXT("->") , NULL , CMD_CURSOR_JUMP_PC }, - {TEXT("Ctrl ->" ) , NULL , CMD_CURSOR_SET_PC }, - {TEXT("Shift ->") , NULL , CMD_CURSOR_JUMP_PC }, // at top - {TEXT("INPUT") , CmdIn , CMD_IN }, + ,{"->" , NULL , CMD_CURSOR_JUMP_PC } + ,{"Ctrl ->" , NULL , CMD_CURSOR_SET_PC } + ,{"Shift ->" , NULL , CMD_CURSOR_JUMP_PC } // at top + ,{"INPUT" , CmdIn , CMD_IN } // Data // Flags - Clear - {TEXT("RC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy - {TEXT("RZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 - {TEXT("RI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 - {TEXT("RD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 - {TEXT("RB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy - {TEXT("RR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 - {TEXT("RV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 - {TEXT("RN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 + ,{"RC" , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" } // 0 // Legacy + ,{"RZ" , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" } // 1 + ,{"RI" , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" } // 2 + ,{"RD" , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" } // 3 + ,{"RB" , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" } // 4 // Legacy + ,{"RR" , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" } // 5 + ,{"RV" , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" } // 6 + ,{"RN" , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" } // 7 // Flags - Set - {TEXT("SC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 - {TEXT("SZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 - {TEXT("SI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 - {TEXT("SD") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 - {TEXT("SB") , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" }, // 4 // Legacy - {TEXT("SR") , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" }, // 5 - {TEXT("SV") , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" }, // 6 - {TEXT("SN") , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" }, // 7 + ,{"SC" , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" } // 0 + ,{"SZ" , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" } // 1 + ,{"SI" , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" } // 2 + ,{"SD" , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" } // 3 + ,{"SB" , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" } // 4 // Legacy + ,{"SR" , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" } // 5 + ,{"SV" , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" } // 6 + ,{"SN" , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" } // 7 // Memory - {TEXT("D") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, // FIXME: Must also work in DATA screen - {TEXT("M1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // alias - {TEXT("M2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 }, // alias + ,{"D" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" } // FIXME: Must also work in DATA screen + ,{"M1" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // alias + ,{"M2" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 } // alias - {TEXT("ME8") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE }, // changed from EB -- bugfix: EB:## ## - {TEXT("ME16") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD }, - {TEXT("MM") , CmdMemoryMove , CMD_MEMORY_MOVE }, - {TEXT("MS") , CmdMemorySearch , CMD_MEMORY_SEARCH }, // CmdMemorySearch - {TEXT("P0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 }, - {TEXT("P1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 }, - {TEXT("P2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 }, - {TEXT("P3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 }, - {TEXT("P4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 }, - {TEXT("REGISTER") , CmdRegisterSet , CMD_REGISTER_SET }, -// {TEXT("RET") , CmdStackReturn , CMD_STACK_RETURN }, - {TEXT("TRACE") , CmdTrace , CMD_TRACE }, + ,{"ME8" , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE } // changed from EB -- bugfix: EB:## ## + ,{"ME16" , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD } + ,{"MM" , CmdMemoryMove , CMD_MEMORY_MOVE } + ,{"MS" , CmdMemorySearch , CMD_MEMORY_SEARCH } // CmdMemorySearch + ,{"P0" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 } + ,{"P1" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 } + ,{"P2" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 } + ,{"P3" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 } + ,{"P4" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 } + ,{"REGISTER" , CmdRegisterSet , CMD_REGISTER_SET } +// ,{"RET" , CmdStackReturn , CMD_STACK_RETURN } + ,{"TRACE" , CmdTrace , CMD_TRACE } -// {TEXT("SYMBOLS") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " }, -// {TEXT("SYMBOLS1") , CmdSymbolsInfo , CMD_SYMBOLS_1 }, -// {TEXT("SYMBOLS2") , CmdSymbolsInfo , CMD_SYMBOLS_2 }, -// {"SYM0" , CmdSymbolsInfo , CMD_SYMBOLS_ROM }, -// {"SYM1" , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT }, -// {"SYM2" , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY }, -// {"SYM3" , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 }, -// {"SYM4" , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 }, -// {"SYM5" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 }, -// {"SYM6" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 }, - {"SYMDOS" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 }, - {"SYMPRO" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS }, +// ,{"SYMBOLS" , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " } +// ,{"SYMBOLS1" , CmdSymbolsInfo , CMD_SYMBOLS_1 } +// ,{"SYMBOLS2" , CmdSymbolsInfo , CMD_SYMBOLS_2 } +// ,{"SYM0" , CmdSymbolsInfo , CMD_SYMBOLS_ROM } +// ,{"SYM1" , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT } +// ,{"SYM2" , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY } +// ,{"SYM3" , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 } +// ,{"SYM4" , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 } +// ,{"SYM5" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 } +// ,{"SYM6" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 } + ,{"SYMDOS" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 } + ,{"SYMPRO" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS } - {TEXT("TEXT40") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X }, - {TEXT("TEXT41") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 }, - {TEXT("TEXT42") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 }, + ,{"TEXT40" , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X } + ,{"TEXT41" , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 } + ,{"TEXT42" , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 } -// {TEXT("WATCH") , CmdWatchAdd , CMD_WATCH_ADD }, - {TEXT("WINDOW") , CmdWindow , CMD_WINDOW }, -// {TEXT("W?") , CmdWatchAdd , CMD_WATCH_ADD }, - {TEXT("ZAP") , CmdNOP , CMD_NOP }, +// ,{"WATCH" , CmdWatchAdd , CMD_WATCH_ADD } + ,{"WINDOW" , CmdWindow , CMD_WINDOW } +// ,{"W?" , CmdWatchAdd , CMD_WATCH_ADD } + ,{"ZAP" , CmdNOP , CMD_NOP } // DEPRECATED -- Probably should be removed in a future version - {TEXT("BENCH") , CmdBenchmarkStart , CMD_BENCHMARK }, - {TEXT("EXITBENCH") , NULL , CMD_BENCHMARK }, // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop - {TEXT("MDB") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? -// {TEXT("MEMORY") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? + ,{"BENCH" , CmdBenchmarkStart , CMD_BENCHMARK } // already hae BENCHMARK + ,{"EXITBENCH" , NULL , CMD_BENCHMARK } // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop + ,{"MDB" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // MemoryDumpByte // Did anyone actually use this?? +// ,{"MEMORY" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // MemoryDumpByte // Did anyone actually use this?? }; const int NUM_COMMANDS_WITH_ALIASES = sizeof(g_aCommands) / sizeof (Command_t); // Determined at compile-time ;-) @@ -387,113 +390,114 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Command_t g_aParameters[] = { // Breakpoint - {TEXT("<=") , NULL, PARAM_BP_LESS_EQUAL }, - {TEXT("<" ) , NULL, PARAM_BP_LESS_THAN }, - {TEXT("=" ) , NULL, PARAM_BP_EQUAL }, - {TEXT("!=") , NULL, PARAM_BP_NOT_EQUAL }, - {TEXT("!" ) , NULL, PARAM_BP_NOT_EQUAL_1 }, - {TEXT(">" ) , NULL, PARAM_BP_GREATER_THAN }, - {TEXT(">=") , NULL, PARAM_BP_GREATER_EQUAL }, - {TEXT("R") , NULL, PARAM_BP_READ }, - {TEXT("?") , NULL, PARAM_BP_READ }, - {TEXT("W") , NULL, PARAM_BP_WRITE }, - {TEXT("@") , NULL, PARAM_BP_WRITE }, - {TEXT("*") , NULL, PARAM_BP_READ_WRITE }, + {"<=" , NULL, PARAM_BP_LESS_EQUAL } + ,{"<" , NULL, PARAM_BP_LESS_THAN } + ,{"=" , NULL, PARAM_BP_EQUAL } + ,{"!=" , NULL, PARAM_BP_NOT_EQUAL } + ,{"!" , NULL, PARAM_BP_NOT_EQUAL_1 } + ,{">" , NULL, PARAM_BP_GREATER_THAN } + ,{">=" , NULL, PARAM_BP_GREATER_EQUAL } + ,{"R" , NULL, PARAM_BP_READ } + ,{"?" , NULL, PARAM_BP_READ } + ,{"W" , NULL, PARAM_BP_WRITE } + ,{"@" , NULL, PARAM_BP_WRITE } + ,{"*" , NULL, PARAM_BP_READ_WRITE } // Regs (for PUSH / POP) - {TEXT("A") , NULL, PARAM_REG_A }, - {TEXT("X") , NULL, PARAM_REG_X }, - {TEXT("Y") , NULL, PARAM_REG_Y }, - {TEXT("PC") , NULL, PARAM_REG_PC }, - {TEXT("S") , NULL, PARAM_REG_SP }, + ,{"A" , NULL, PARAM_REG_A } + ,{"X" , NULL, PARAM_REG_X } + ,{"Y" , NULL, PARAM_REG_Y } + ,{"PC" , NULL, PARAM_REG_PC } + ,{"S" , NULL, PARAM_REG_SP } +// ,{"G" , NULL, PARAM_REG_PC } // Flags - {TEXT("P") , NULL, PARAM_FLAGS }, - {TEXT("C") , NULL, PARAM_FLAG_C }, // ---- ---1 Carry - {TEXT("Z") , NULL, PARAM_FLAG_Z }, // ---- --1- Zero - {TEXT("I") , NULL, PARAM_FLAG_I }, // ---- -1-- Interrupt - {TEXT("D") , NULL, PARAM_FLAG_D }, // ---- 1--- Decimal - {TEXT("B") , NULL, PARAM_FLAG_B }, // ---1 ---- Break - {TEXT("R") , NULL, PARAM_FLAG_R }, // --1- ---- Reserved - {TEXT("V") , NULL, PARAM_FLAG_V }, // -1-- ---- Overflow - {TEXT("N") , NULL, PARAM_FLAG_N }, // 1--- ---- Sign + ,{"P" , NULL, PARAM_FLAGS } + ,{"C" , NULL, PARAM_FLAG_C } // ---- ---1 Carry + ,{"Z" , NULL, PARAM_FLAG_Z } // ---- --1- Zero + ,{"I" , NULL, PARAM_FLAG_I } // ---- -1-- Interrupt + ,{"D" , NULL, PARAM_FLAG_D } // ---- 1--- Decimal + ,{"B" , NULL, PARAM_FLAG_B } // ---1 ---- Break + ,{"R" , NULL, PARAM_FLAG_R } // --1- ---- Reserved + ,{"V" , NULL, PARAM_FLAG_V } // -1-- ---- Overflow + ,{"N" , NULL, PARAM_FLAG_N } // 1--- ---- Sign // Disasm - {TEXT("BRANCH") , NULL, PARAM_CONFIG_BRANCH }, - {TEXT("COLON") , NULL, PARAM_CONFIG_COLON }, - {TEXT("OPCODE") , NULL, PARAM_CONFIG_OPCODE }, - {TEXT("POINTER") , NULL, PARAM_CONFIG_POINTER }, - {TEXT("SPACES") , NULL, PARAM_CONFIG_SPACES }, - {TEXT("TARGET") , NULL, PARAM_CONFIG_TARGET }, + ,{"BRANCH" , NULL, PARAM_CONFIG_BRANCH } + ,{"COLON" , NULL, PARAM_CONFIG_COLON } + ,{"OPCODE" , NULL, PARAM_CONFIG_OPCODE } + ,{"POINTER" , NULL, PARAM_CONFIG_POINTER } + ,{"SPACES" , NULL, PARAM_CONFIG_SPACES } + ,{"TARGET" , NULL, PARAM_CONFIG_TARGET } // Disk - {TEXT("EJECT") , NULL, PARAM_DISK_EJECT }, - {TEXT("INFO") , NULL, PARAM_DISK_INFO }, - {TEXT("PROTECT") , NULL, PARAM_DISK_PROTECT }, - {TEXT("READ") , NULL, PARAM_DISK_READ }, + ,{"EJECT" , NULL, PARAM_DISK_EJECT } + ,{"INFO" , NULL, PARAM_DISK_INFO } + ,{"PROTECT" , NULL, PARAM_DISK_PROTECT } + ,{"READ" , NULL, PARAM_DISK_READ } // Font (Config) - {TEXT("MODE") , NULL, PARAM_FONT_MODE }, // also INFO, CONSOLE, DISASM (from Window) + ,{"MODE" , NULL, PARAM_FONT_MODE } // also INFO, CONSOLE, DISASM (from Window) // General - {TEXT("FIND") , NULL, PARAM_FIND }, - {TEXT("BRANCH") , NULL, PARAM_BRANCH }, - {"CATEGORY" , NULL, PARAM_CATEGORY }, - {TEXT("CLEAR") , NULL, PARAM_CLEAR }, - {TEXT("LOAD") , NULL, PARAM_LOAD }, - {TEXT("LIST") , NULL, PARAM_LIST }, - {TEXT("OFF") , NULL, PARAM_OFF }, - {TEXT("ON") , NULL, PARAM_ON }, - {TEXT("RESET") , NULL, PARAM_RESET }, - {TEXT("SAVE") , NULL, PARAM_SAVE }, - {TEXT("START") , NULL, PARAM_START }, // benchmark - {TEXT("STOP") , NULL, PARAM_STOP }, // benchmark + ,{"FIND" , NULL, PARAM_FIND } + ,{"BRANCH" , NULL, PARAM_BRANCH } + ,{"CATEGORY" , NULL, PARAM_CATEGORY } + ,{"CLEAR" , NULL, PARAM_CLEAR } + ,{"LOAD" , NULL, PARAM_LOAD } + ,{"LIST" , NULL, PARAM_LIST } + ,{"OFF" , NULL, PARAM_OFF } + ,{"ON" , NULL, PARAM_ON } + ,{"RESET" , NULL, PARAM_RESET } + ,{"SAVE" , NULL, PARAM_SAVE } + ,{"START" , NULL, PARAM_START } // benchmark + ,{"STOP" , NULL, PARAM_STOP } // benchmark // Help Categories - {"*" , NULL, PARAM_WILDSTAR }, - {"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS }, - {"BREAKPOINTS" , NULL, PARAM_CAT_BREAKPOINTS }, - {"CONFIG" , NULL, PARAM_CAT_CONFIG }, - {"CPU" , NULL, PARAM_CAT_CPU }, -// {TEXT("EXPRESSION") , - {"FLAGS" , NULL, PARAM_CAT_FLAGS }, - {"HELP" , NULL, PARAM_CAT_HELP }, - {"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD }, - {"MEMORY" , NULL, PARAM_CAT_MEMORY }, // alias // SOURCE [SYMBOLS] [MEMORY] filename - {"OUTPUT" , NULL, PARAM_CAT_OUTPUT }, - {"OPERATORS" , NULL, PARAM_CAT_OPERATORS }, - {"RANGE" , NULL, PARAM_CAT_RANGE }, -// {TEXT("REGISTERS") , NULL, PARAM_CAT_REGISTERS }, - {"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS }, - {"VIEW" , NULL, PARAM_CAT_VIEW }, - {"WATCHES" , NULL, PARAM_CAT_WATCHES }, - {"WINDOW" , NULL, PARAM_CAT_WINDOW }, - {"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE }, + ,{"*" , NULL, PARAM_WILDSTAR } + ,{"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS } + ,{"BREAKPOINTS", NULL, PARAM_CAT_BREAKPOINTS } + ,{"CONFIG" , NULL, PARAM_CAT_CONFIG } + ,{"CPU" , NULL, PARAM_CAT_CPU } +// ,{"EXPRESSION" , + ,{"FLAGS" , NULL, PARAM_CAT_FLAGS } + ,{"HELP" , NULL, PARAM_CAT_HELP } + ,{"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD } + ,{"MEMORY" , NULL, PARAM_CAT_MEMORY } // alias // SOURCE [SYMBOLS] [MEMORY] filename + ,{"OUTPUT" , NULL, PARAM_CAT_OUTPUT } + ,{"OPERATORS" , NULL, PARAM_CAT_OPERATORS } + ,{"RANGE" , NULL, PARAM_CAT_RANGE } +// ,{"REGISTERS" NULL, PARAM_CAT_REGISTERS } + ,{"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS } + ,{"VIEW" , NULL, PARAM_CAT_VIEW } + ,{"WATCHES" , NULL, PARAM_CAT_WATCHES } + ,{"WINDOW" , NULL, PARAM_CAT_WINDOW } + ,{"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE } // Memory - {TEXT("?") , NULL, PARAM_MEM_SEARCH_WILD }, -// {TEXT("*") , NULL, PARAM_MEM_SEARCH_BYTE }, + ,{"?" , NULL, PARAM_MEM_SEARCH_WILD } +// ,{"*" , NULL, PARAM_MEM_SEARCH_BYTE } // Source level debugging - {TEXT("MEM") , NULL, PARAM_SRC_MEMORY }, - {TEXT("MEMORY") , NULL, PARAM_SRC_MEMORY }, - {TEXT("SYM") , NULL, PARAM_SRC_SYMBOLS }, - {TEXT("SYMBOLS") , NULL, PARAM_SRC_SYMBOLS }, - {TEXT("MERLIN") , NULL, PARAM_SRC_MERLIN }, - {TEXT("ORCA") , NULL, PARAM_SRC_ORCA }, + ,{"MEM" , NULL, PARAM_SRC_MEMORY } + ,{"MEMORY" , NULL, PARAM_SRC_MEMORY } + ,{"SYM" , NULL, PARAM_SRC_SYMBOLS } + ,{"SYMBOLS" , NULL, PARAM_SRC_SYMBOLS } + ,{"MERLIN" , NULL, PARAM_SRC_MERLIN } + ,{"ORCA" , NULL, PARAM_SRC_ORCA } // View -// {TEXT("VIEW") , NULL, PARAM_SRC_??? }, +// ,{"VIEW") , NULL, PARAM_SRC_??? }, // Window Win Cmd WinEffects CmdEffects - {TEXT("CODE") , NULL, PARAM_CODE }, // x x code win only switch to code window -// {TEXT("CODE1") , NULL, PARAM_CODE_1 }, // - x code/data win - {TEXT("CODE2") , NULL, PARAM_CODE_2 }, // - x code/data win - {TEXT("CONSOLE") , NULL, PARAM_CONSOLE }, // x - switch to console window - {TEXT("DATA") , NULL, PARAM_DATA }, // x x data win only switch to data window -// {TEXT("DATA1") , NULL, PARAM_DATA_1 }, // - x code/data win - {TEXT("DATA2") , NULL, PARAM_DATA_2 }, // - x code/data win - {TEXT("DISASM") , NULL, PARAM_DISASM }, // - {TEXT("INFO") , NULL, PARAM_INFO }, // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP - {TEXT("SOURCE") , NULL, PARAM_SOURCE }, // x x switch to source window - {TEXT("SRC") , NULL, PARAM_SOURCE }, // alias -// {TEXT("SOURCE_1") , NULL, PARAM_SOURCE_1 }, // - x code/data - {TEXT("SOURCE2 ") , NULL, PARAM_SOURCE_2 }, // - x - {TEXT("SYMBOLS") , NULL, PARAM_SYMBOLS }, // x x code/data win switch to symbols window - {TEXT("SYM") , NULL, PARAM_SYMBOLS }, // alias x SOURCE [SYM] [MEM] filename -// {TEXT("SYMBOL1") , NULL, PARAM_SYMBOL_1 }, // - x code/data win - {TEXT("SYMBOL2") , NULL, PARAM_SYMBOL_2 }, // - x code/data win + ,{"CODE" , NULL, PARAM_CODE } // x x code win only switch to code window +// ,{"CODE1" , NULL, PARAM_CODE_1 } // - x code/data win + ,{"CODE2" , NULL, PARAM_CODE_2 } // - x code/data win + ,{"CONSOLE" , NULL, PARAM_CONSOLE } // x - switch to console window + ,{"DATA" , NULL, PARAM_DATA } // x x data win only switch to data window +// ,{"DATA1" , NULL, PARAM_DATA_1 } // - x code/data win + ,{"DATA2" , NULL, PARAM_DATA_2 } // - x code/data win + ,{"DISASM" , NULL, PARAM_DISASM } // + ,{"INFO" , NULL, PARAM_INFO } // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP + ,{"SOURCE" , NULL, PARAM_SOURCE } // x x switch to source window + ,{"SRC" , NULL, PARAM_SOURCE } // alias +// ,{"SOURCE_1" , NULL, PARAM_SOURCE_1 } // - x code/data + ,{"SOURCE2 " , NULL, PARAM_SOURCE_2 } // - x + ,{"SYMBOLS" , NULL, PARAM_SYMBOLS } // x x code/data win switch to symbols window + ,{"SYM" , NULL, PARAM_SYMBOLS } // alias x SOURCE [SYM] [MEM] filename +// ,{"SYMBOL1" , NULL, PARAM_SYMBOL_1 } // - x code/data win + ,{"SYMBOL2" , NULL, PARAM_SYMBOL_2 } // - x code/data win // Internal Consistency Check - { DEBUGGER__PARAMS_VERIFY_TXT__, NULL, NUM_PARAMS }, + ,{DEBUGGER__PARAMS_VERIFY_TXT__,NULL,NUM_PARAMS} }; //=========================================================================== @@ -507,7 +511,7 @@ void VerifyDebuggerCommandTable() if ( g_aCommands[ iCmd ].iCommand != iCmd) { sprintf( sText, "*** ERROR *** Enumerated Commands mis-matched at #%d!", iCmd ); - MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); + MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); PostQuitMessage( 1 ); } } @@ -516,14 +520,14 @@ void VerifyDebuggerCommandTable() if (strcmp( g_aCommands[ NUM_COMMANDS ].m_sName, DEBUGGER__COMMANDS_VERIFY_TXT__)) { sprintf( sText, "*** ERROR *** Total Commands mis-matched!" ); - MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); + MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); PostQuitMessage( 1 ); } if (strcmp( g_aParameters[ NUM_PARAMS ].m_sName, DEBUGGER__PARAMS_VERIFY_TXT__)) { sprintf( sText, "*** ERROR *** Total Parameters mis-matched!" ); - MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); + MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); PostQuitMessage( 2 ); } } From c13fb849a5a7541b0131d834ba80d21450414a28 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 8 Jan 2015 12:05:23 -0800 Subject: [PATCH 074/121] Added NTSC_VideoGetChromaTable(), _NTSC_VideoInitChroma() --- source/NTSC.cpp | 68 ++++++++++++++++++++++++++++++++++--------------- source/NTSC.h | 3 +++ 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1f956b71..39a77d49 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -174,10 +174,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA const uint32_t ALPHA32_MASK = 0xFF000000; // Win32: aarrggbb - static bgra_t g_aBnWMonitor [NTSC_NUM_SEQUENCES]; - static bgra_t g_aHueMonitor[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; - static bgra_t g_aBnwColorTV [NTSC_NUM_SEQUENCES]; - static bgra_t g_aHueColorTV[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; +/*extern*/ uint32_t g_nChromaSize = 0; // for NTSC_VideoGetChromaTable() + static bgra_t g_aBnWMonitor [NTSC_NUM_SEQUENCES]; + static bgra_t g_aHueMonitor[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; + static bgra_t g_aBnwColorTV [NTSC_NUM_SEQUENCES]; + static bgra_t g_aHueColorTV[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES]; // g_aBnWMonitor * g_nMonochromeRGB -> g_aBnWMonitorCustom // g_aBnwColorTV * g_nMonochromeRGB -> g_aBnWColorTVCustom @@ -1390,6 +1391,43 @@ void updateScreenText80 (long cycles6502) // Functions (Public) _____________________________________________________________________________ +//=========================================================================== +uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV ) +{ + if( bHueTypeMonochrome ) + { + g_nChromaSize = sizeof( g_aBnwColorTV ); + + if( bMonitorTypeColorTV ) + return (uint32_t*) g_aBnwColorTV; + else + return (uint32_t*) g_aBnWMonitor; + } else { + g_nChromaSize = sizeof( g_aHueColorTV ); + + if( bMonitorTypeColorTV ) + return (uint32_t*) g_aHueColorTV; + else + return (uint32_t*) g_aHueMonitor; + } +} + +//=========================================================================== +uint16_t NTSC_VideoGetScannerAddress ( unsigned long cycles6502 ) +{ + (void)cycles6502; + + int nHires = (g_uVideoMode & VF_HIRES) && !(g_uVideoMode & VF_TEXT); // (SW_HIRES && !SW_TEXT) ? 1 : 0; + if( nHires ) + updateVideoScannerAddressHGR(); + else + updateVideoScannerAddressTXT(); + + // Required for ANSI STORY vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80 + uint8_t hclock = (g_nVideoClockHorz + VIDEO_SCANNER_MAX_HORZ - 2) % VIDEO_SCANNER_MAX_HORZ; // Optimization: (h-2) + return g_aHorzClockMemAddress[ hclock ]; +} + //=========================================================================== void NTSC_SetVideoTextMode( int cols ) { @@ -1537,22 +1575,6 @@ _mono: } } -//=========================================================================== -uint16_t NTSC_VideoGetScannerAddress ( unsigned long cycles6502 ) -{ - (void)cycles6502; - - int nHires = (g_uVideoMode & VF_HIRES) && !(g_uVideoMode & VF_TEXT); // (SW_HIRES && !SW_TEXT) ? 1 : 0; - if( nHires ) - updateVideoScannerAddressHGR(); - else - updateVideoScannerAddressTXT(); - - // Required for ANSI STORY vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80 - uint8_t hclock = (g_nVideoClockHorz + VIDEO_SCANNER_MAX_HORZ - 2) % VIDEO_SCANNER_MAX_HORZ; // Optimization: (h-2) - return g_aHorzClockMemAddress[ hclock ]; -} - //=========================================================================== void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit { @@ -1643,6 +1665,12 @@ void NTSC_VideoInitAppleType () } +//=========================================================================== +void NTSC_VideoInitChroma() +{ + initChromaPhaseTables(); +} + //=========================================================================== bool NTSC_VideoIsVbl () { diff --git a/source/NTSC.h b/source/NTSC.h index 4a050284..3c53caf4 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -4,14 +4,17 @@ // Globals (Public) extern uint16_t g_nVideoClockVert; extern uint16_t g_nVideoClockHorz; + extern uint32_t g_nChromaSize; // Prototypes (Public) ________________________________________________ extern void NTSC_SetVideoMode( int bVideoModeFlags ); extern void NTSC_SetVideoStyle(); extern void NTSC_SetVideoTextMode( int cols ); + extern uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV ); extern uint16_t NTSC_VideoGetScannerAddress( unsigned long cycles6502 ); extern void NTSC_VideoInit( uint8_t *pFramebuffer ); extern void NTSC_VideoInitAppleType (); + extern void NTSC_VideoInitChroma(); extern bool NTSC_VideoIsVbl(); extern void NTSC_VideoUpdateCycles( long cycles6502 ); From 94193215b915b0a29503581f45d76fc3d2d3d225 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 8 Jan 2015 12:05:53 -0800 Subject: [PATCH 075/121] Cleanup whitespace --- source/Debugger/Debugger_Color.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Debugger/Debugger_Color.cpp b/source/Debugger/Debugger_Color.cpp index 6a930c49..91baba7e 100644 --- a/source/Debugger/Debugger_Color.cpp +++ b/source/Debugger/Debugger_Color.cpp @@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA RGB(255,255, 0), RGB(223,223, 0), RGB(191,191, 0), RGB(159,159, 0), RGB(127,127, 0), RGB( 95, 95, 0), RGB( 63, 63, 0), RGB( 31, 31, 0), // 011 // Yellow RGB( 0, 0,255), RGB( 0, 0,223), RGB( 0, 0,191), RGB( 0, 0,159), RGB( 0, 0,127), RGB( 0, 0, 95), RGB( 0, 0, 63), RGB( 0, 0, 31), // 100 // Blue RGB(255, 0,255), RGB(223, 0,223), RGB(191, 0,191), RGB(159, 0,159), RGB(127, 0,127), RGB( 95, 0, 95), RGB( 63, 0, 63), RGB( 31, 0, 31), // 101 // Magenta - RGB( 0,255,255), RGB( 0,223,223), RGB( 0,191,191), RGB( 0,159,159), RGB( 0,127,127), RGB( 0, 95, 95), RGB( 0, 63, 63), RGB( 0, 31, 31), // 110 // Cyan + RGB( 0,255,255), RGB( 0,223,223), RGB( 0,191,191), RGB( 0,159,159), RGB( 0,127,127), RGB( 0, 95, 95), RGB( 0, 63, 63), RGB( 0, 31, 31), // 110 // Cyan RGB(255,255,255), RGB(223,223,223), RGB(191,191,191), RGB(159,159,159), RGB(127,127,127), RGB( 95, 95, 95), RGB( 63, 63, 63), RGB( 31, 31, 31), // 111 // White/Gray // Custom Colors From ae6f1c9f0fd01ccd01b6e9d290941b3579918543 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Thu, 8 Jan 2015 12:15:19 -0800 Subject: [PATCH 076/121] Debugger: Added: ntsc save [filename], ntsc load [filename] --- source/Debugger/Debug.cpp | 193 +++++++++++++++- source/Debugger/Debugger_Commands.cpp | 1 + source/Debugger/Debugger_Types.h | 317 +++++++++++++------------- source/Video.cpp | 3 +- 4 files changed, 345 insertions(+), 169 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index a8d6e2a7..a9296ae5 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "..\Frame.h" #include "..\Keyboard.h" #include "..\Memory.h" +#include "..\NTSC.h" #include "..\Video.h" // #define DEBUG_COMMAND_HELP 1 @@ -47,7 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ALLOW_INPUT_LOWERCASE 1 // See /docs/Debugger_Changelog.txt for full details - const int DEBUGGER_VERSION = MAKE_VERSION(2,8,0,8); + const int DEBUGGER_VERSION = MAKE_VERSION(2,9,0,0); // Public _________________________________________________________________________________________ @@ -379,6 +380,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA WORD DisasmCalcAddressFromLines( WORD iAddress, int nLines ); +// File _______________________________________________________________________ + +int _GetFileSize( FILE *hFile ) +{ + fseek( hFile, 0, SEEK_END ); + int nFileBytes = ftell( hFile ); + fseek( hFile, 0, SEEK_SET ); + + return nFileBytes; +} + + + // Bookmarks __________________________________________________________________ @@ -4108,9 +4122,7 @@ Update_t CmdMemoryLoad (int nArgs) FILE *hFile = fopen( sLoadSaveFilePath, "rb" ); if (hFile) { - fseek( hFile, 0, SEEK_END ); - int nFileBytes = ftell( hFile ); - fseek( hFile, 0, SEEK_SET ); + int nFileBytes = _GetFileSize( hFile ); if (nFileBytes > _6502_MEM_END) nFileBytes = _6502_MEM_END + 1; // Bank-switched RAMR/ROM is only 16-bit @@ -4230,12 +4242,12 @@ Update_t CmdMemoryLoad (int nArgs) ,{ ".hgr2", 0x4000, 0x2000 } // TODO: extension ".dhgr", ".dhgr2" }; - const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t ); + const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t ); const KnownFileType_t *pFileType = NULL; char *pFileName = g_aArgs[ 1 ].sArg; int nLen = strlen( pFileName ); - char *pEnd = pFileName + + nLen - 1; + char *pEnd = pFileName + nLen - 1; while( pEnd > pFileName ) { if( *pEnd == '.' ) @@ -4310,9 +4322,7 @@ Update_t CmdMemoryLoad (int nArgs) FILE *hFile = fopen( sLoadSaveFilePath, "rb" ); if (hFile) { - fseek( hFile, 0, SEEK_END ); - int nFileBytes = ftell( hFile ); - fseek( hFile, 0, SEEK_SET ); + int nFileBytes = _GetFileSize( hFile ); if (nFileBytes > _6502_MEM_END) nFileBytes = _6502_MEM_END + 1; // Bank-switched RAM/ROM is only 16-bit @@ -4414,7 +4424,6 @@ Update_t CmdMemoryMove (int nArgs) return UPDATE_CONSOLE_DISPLAY; } - //=========================================================================== #if 0 // Original Update_t CmdMemorySave (int nArgs) @@ -4665,6 +4674,7 @@ Update_t CmdMemorySave (int nArgs) { ConsoleBufferPush( TEXT( "Warning: File already exists. Overwriting." ) ); fclose( hFile ); + // TODO: BUG: Is this a bug/feature that we can over-write files and the user has no control over that? } hFile = fopen( sLoadSaveFilePath, "wb" ); @@ -4855,6 +4865,169 @@ void Util_CopyTextToClipboard ( const size_t nSize, const char *pText ) // GlobalFree() ?? } +//=========================================================================== +Update_t CmdNTSC (int nArgs) +{ + int iParam; + int nFound = FindParam( g_aArgs[ 1 ].sArg, MATCH_EXACT, iParam, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END ); + + struct KnownFileType_t + { + char *pExtension; + }; + + const KnownFileType_t aFileTypes[] = + { + { "" } // n/a + ,{ ".bmp" } + ,{ ".data" } +// ,{ ".raw" } +// ,{ ".ntsc" } + }; + const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t ); + const KnownFileType_t *pFileType = NULL; + + char *pFileName = (nArgs > 1) ? g_aArgs[ 2 ].sArg : ""; + int nLen = strlen( pFileName ); + char *pEnd = pFileName + nLen - 1; + while( pEnd > pFileName ) + { + if( *pEnd == '.' ) + { + for( int i = 1; i < nFileTypes; i++ ) + { + if( strcmp( pEnd, aFileTypes[i].pExtension ) == 0 ) + { + pFileType = &aFileTypes[i]; + break; + } + } + } + + if( pFileType ) + break; + + pEnd--; + } + + if( nLen == 0 ) + pFileName = "AppleWinNTSC4096x4@32.data"; + + static TCHAR sPaletteFilePath[ MAX_PATH ]; + _tcscpy( sPaletteFilePath, g_sCurrentDir ); + _tcscat( sPaletteFilePath, pFileName ); + + class ConsoleFilename + { + public: + static void update( const char *pPrefixText ) + { + TCHAR text[ CONSOLE_WIDTH ] = TEXT(""); + sprintf( text, "%s: %s", pPrefixText, sPaletteFilePath ); + ConsoleBufferPush( text ); // "Saved." + } + }; + + class Swizzle32 + { + public: + static void swizzleRB( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) + { + const uint8_t* pEnd = pSrc + nSize; + while ( pSrc < pEnd ) + { + *pDst++ = pSrc[2]; + *pDst++ = pSrc[1]; + *pDst++ = pSrc[0]; + *pDst++ = pSrc[3]; + + pSrc += 4; + } + } + }; + + uint32_t* pChromaTable = NTSC_VideoGetChromaTable( false, false ); + + if (nFound) + { + if (iParam == PARAM_RESET) + { + NTSC_VideoInitChroma(); + ConsoleBufferPush( TEXT(" Resetting NTSC palette." ) ); + } + else + if (iParam == PARAM_SAVE) + { + FILE *pFile = fopen( sPaletteFilePath, "w+b" ); + if( pFile ) + { + size_t nWrote = 0; + + // Write BMP + // need to save 32-bit bpp as 24-bit bpp + // VideoSaveScreenShot() + + // Write RAW + uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; + Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + nWrote = fwrite( pSwizzled, g_nChromaSize, 1, pFile ); + + delete [] pSwizzled; + fclose( pFile ); + + if (nWrote == 1) + { + ConsoleFilename::update( "Saved" ); + } + else + ConsoleBufferPush( TEXT( "Error saving." ) ); + } + else + { + ConsoleFilename::update( "File: " ); + ConsoleBufferPush( TEXT( "Error couldn't open file for writing." ) ); + } + } + else + if (iParam == PARAM_LOAD) + { + FILE *pFile = fopen( sPaletteFilePath, "rb" ); + if( pFile ) + { + // Get File Size + size_t nFileSize = _GetFileSize( pFile ); + + if( nFileSize != g_nChromaSize ) + { + fclose( pFile ); + return ConsoleUpdate(); + } + + // BMP + // RAW + uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; + size_t nRead = fread( pSwizzled, g_nChromaSize, 1, pFile ); + Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); + + delete [] pSwizzled; + fclose( pFile ); + + ConsoleFilename::update( "Loaded" ); + } + else + { + ConsoleFilename::update( "File: " ); + ConsoleBufferPush( TEXT( "Error couldn't open file for reading." ) ); + } + } + else + return HelpLastCommand(); + } +// else + + return ConsoleUpdate(); +} + //=========================================================================== int CmdTextSave (int nArgs) diff --git a/source/Debugger/Debugger_Commands.cpp b/source/Debugger/Debugger_Commands.cpp index 84840c81..105561d2 100644 --- a/source/Debugger/Debugger_Commands.cpp +++ b/source/Debugger/Debugger_Commands.cpp @@ -204,6 +204,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ,{"SH" , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" } ,{"F" , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" } + ,{"NTSC" , CmdNTSC , CMD_NTSC , "Save/Load the NTSC palette" } ,{"TSAVE" , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" } // Output / Scripts ,{"CALC" , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" } diff --git a/source/Debugger/Debugger_Types.h b/source/Debugger/Debugger_Types.h index b96d4b88..a59259cb 100644 --- a/source/Debugger/Debugger_Types.h +++ b/source/Debugger/Debugger_Types.h @@ -442,6 +442,7 @@ // , CMD_MEMORY_SEARCH_APPLE // Flashing Chars, Hi-Bit Set , CMD_MEMORY_SEARCH_HEX , CMD_MEMORY_FILL + , CMD_NTSC , CMD_TEXT_SAVE // Output , CMD_OUTPUT_CALC @@ -555,7 +556,7 @@ }; // Assembler - Update_t CmdAssemble (int nArgs); + Update_t CmdAssemble (int nArgs); // Disassembler Data Update_t CmdDisasmDataDefCode (int nArgs); @@ -577,89 +578,89 @@ Update_t CmdDisasmDataDefAddress16(int nArgs); // CPU - Update_t CmdCursorJumpPC(int nArgs); - Update_t CmdCursorSetPC (int nArgs); - Update_t CmdBreakInvalid(int nArgs); // Breakpoint IFF Full-speed! - Update_t CmdBreakOpcode (int nArgs); // Breakpoint IFF Full-speed! - Update_t CmdGo (int nArgs); - Update_t CmdIn (int nArgs); - Update_t CmdKey (int nArgs); - Update_t CmdJSR (int nArgs); - Update_t CmdNOP (int nArgs); - Update_t CmdOut (int nArgs); - Update_t CmdStepOver (int nArgs); - Update_t CmdStepOut (int nArgs); - Update_t CmdTrace (int nArgs); // alias for CmdStepIn - Update_t CmdTraceFile (int nArgs); - Update_t CmdTraceLine (int nArgs); - Update_t CmdUnassemble (int nArgs); // code dump, aka, Unassemble + Update_t CmdCursorJumpPC (int nArgs); + Update_t CmdCursorSetPC (int nArgs); + Update_t CmdBreakInvalid (int nArgs); // Breakpoint IFF Full-speed! + Update_t CmdBreakOpcode (int nArgs); // Breakpoint IFF Full-speed! + Update_t CmdGo (int nArgs); + Update_t CmdIn (int nArgs); + Update_t CmdKey (int nArgs); + Update_t CmdJSR (int nArgs); + Update_t CmdNOP (int nArgs); + Update_t CmdOut (int nArgs); + Update_t CmdStepOver (int nArgs); + Update_t CmdStepOut (int nArgs); + Update_t CmdTrace (int nArgs); // alias for CmdStepIn + Update_t CmdTraceFile (int nArgs); + Update_t CmdTraceLine (int nArgs); + Update_t CmdUnassemble (int nArgs); // code dump, aka, Unassemble // Bookmarks - Update_t CmdBookmark (int nArgs); - Update_t CmdBookmarkAdd (int nArgs); - Update_t CmdBookmarkClear (int nArgs); - Update_t CmdBookmarkList (int nArgs); - Update_t CmdBookmarkGoto (int nArgs); -// Update_t CmdBookmarkLoad (int nArgs); - Update_t CmdBookmarkSave (int nArgs); + Update_t CmdBookmark (int nArgs); + Update_t CmdBookmarkAdd (int nArgs); + Update_t CmdBookmarkClear (int nArgs); + Update_t CmdBookmarkList (int nArgs); + Update_t CmdBookmarkGoto (int nArgs); +// Update_t CmdBookmarkLoad (int nArgs); + Update_t CmdBookmarkSave (int nArgs); // Breakpoints - Update_t CmdBreakpoint (int nArgs); - Update_t CmdBreakpointAddSmart(int nArgs); - Update_t CmdBreakpointAddReg (int nArgs); - Update_t CmdBreakpointAddPC (int nArgs); - Update_t CmdBreakpointAddIO (int nArgs); - Update_t CmdBreakpointAddMem (int nArgs); - Update_t CmdBreakpointClear (int nArgs); - Update_t CmdBreakpointDisable (int nArgs); - Update_t CmdBreakpointEdit (int nArgs); - Update_t CmdBreakpointEnable (int nArgs); - Update_t CmdBreakpointList (int nArgs); -// Update_t CmdBreakpointLoad (int nArgs); - Update_t CmdBreakpointSave (int nArgs); + Update_t CmdBreakpoint (int nArgs); + Update_t CmdBreakpointAddSmart (int nArgs); + Update_t CmdBreakpointAddReg (int nArgs); + Update_t CmdBreakpointAddPC (int nArgs); + Update_t CmdBreakpointAddIO (int nArgs); + Update_t CmdBreakpointAddMem (int nArgs); + Update_t CmdBreakpointClear (int nArgs); + Update_t CmdBreakpointDisable (int nArgs); + Update_t CmdBreakpointEdit (int nArgs); + Update_t CmdBreakpointEnable (int nArgs); + Update_t CmdBreakpointList (int nArgs); +// Update_t CmdBreakpointLoad (int nArgs); + Update_t CmdBreakpointSave (int nArgs); // Benchmark - Update_t CmdBenchmark (int nArgs); - Update_t CmdBenchmarkStart (int nArgs); //Update_t CmdSetupBenchmark (int nArgs); - Update_t CmdBenchmarkStop (int nArgs); //Update_t CmdExtBenchmark (int nArgs); - Update_t CmdProfile (int nArgs); - Update_t CmdProfileStart (int nArgs); - Update_t CmdProfileStop (int nArgs); + Update_t CmdBenchmark (int nArgs); + Update_t CmdBenchmarkStart (int nArgs); //Update_t CmdSetupBenchmark (int nArgs); + Update_t CmdBenchmarkStop (int nArgs); //Update_t CmdExtBenchmark (int nArgs); + Update_t CmdProfile (int nArgs); + Update_t CmdProfileStart (int nArgs); + Update_t CmdProfileStop (int nArgs); // Config -// Update_t CmdConfigMenu (int nArgs); -// Update_t CmdConfigBase (int nArgs); -// Update_t CmdConfigBaseHex (int nArgs); -// Update_t CmdConfigBaseDec (int nArgs); - Update_t CmdConfigColorMono (int nArgs); - Update_t CmdConfigDisasm (int nArgs); - Update_t CmdConfigFont (int nArgs); - Update_t CmdConfigHColor (int nArgs); - Update_t CmdConfigLoad (int nArgs); - Update_t CmdConfigSave (int nArgs); - Update_t CmdConfigSetFont (int nArgs); - Update_t CmdConfigGetFont (int nArgs); - Update_t CmdConfigGetDebugDir (int nArgs); - Update_t CmdConfigSetDebugDir (int nArgs); +// Update_t CmdConfigMenu (int nArgs); +// Update_t CmdConfigBase (int nArgs); +// Update_t CmdConfigBaseHex (int nArgs); +// Update_t CmdConfigBaseDec (int nArgs); + Update_t CmdConfigColorMono (int nArgs); + Update_t CmdConfigDisasm (int nArgs); + Update_t CmdConfigFont (int nArgs); + Update_t CmdConfigHColor (int nArgs); + Update_t CmdConfigLoad (int nArgs); + Update_t CmdConfigSave (int nArgs); + Update_t CmdConfigSetFont (int nArgs); + Update_t CmdConfigGetFont (int nArgs); + Update_t CmdConfigGetDebugDir (int nArgs); + Update_t CmdConfigSetDebugDir (int nArgs); // Cursor - Update_t CmdCursorFollowTarget(int nArgs); - Update_t CmdCursorLineDown (int nArgs); - Update_t CmdCursorLineUp (int nArgs); - Update_t CmdCursorJumpRetAddr (int nArgs); - Update_t CmdCursorRunUntil (int nArgs); - Update_t CmdCursorPageDown (int nArgs); - Update_t CmdCursorPageDown256 (int nArgs); - Update_t CmdCursorPageDown4K (int nArgs); - Update_t CmdCursorPageUp (int nArgs); - Update_t CmdCursorPageUp256 (int nArgs); - Update_t CmdCursorPageUp4K (int nArgs); + Update_t CmdCursorFollowTarget (int nArgs); + Update_t CmdCursorLineDown (int nArgs); + Update_t CmdCursorLineUp (int nArgs); + Update_t CmdCursorJumpRetAddr (int nArgs); + Update_t CmdCursorRunUntil (int nArgs); + Update_t CmdCursorPageDown (int nArgs); + Update_t CmdCursorPageDown256 (int nArgs); + Update_t CmdCursorPageDown4K (int nArgs); + Update_t CmdCursorPageUp (int nArgs); + Update_t CmdCursorPageUp256 (int nArgs); + Update_t CmdCursorPageUp4K (int nArgs); // Disk - Update_t CmdDisk (int nArgs); + Update_t CmdDisk (int nArgs); // Help - Update_t CmdHelpList (int nArgs); - Update_t CmdHelpSpecific (int Argss); - Update_t CmdVersion (int nArgs); - Update_t CmdMOTD (int nArgs); + Update_t CmdHelpList (int nArgs); + Update_t CmdHelpSpecific (int Argss); + Update_t CmdVersion (int nArgs); + Update_t CmdMOTD (int nArgs); // Flags - Update_t CmdFlag (int nArgs); - Update_t CmdFlagClear (int nArgs); - Update_t CmdFlagSet (int nArgs); + Update_t CmdFlag (int nArgs); + Update_t CmdFlagClear (int nArgs); + Update_t CmdFlagSet (int nArgs); // Memory (Data) Update_t CmdMemoryCompare (int nArgs); Update_t CmdMemoryMiniDumpHex (int nArgs); @@ -672,13 +673,14 @@ Update_t CmdMemoryEnterByte (int nArgs); Update_t CmdMemoryEnterWord (int nArgs); Update_t CmdMemoryFill (int nArgs); + Update_t CmdNTSC (int nArgs); Update_t CmdTextSave (int nArgs); Update_t CmdMemoryLoad (int nArgs); Update_t CmdMemoryMove (int nArgs); Update_t CmdMemorySave (int nArgs); Update_t CmdMemorySearch (int nArgs); - Update_t _SearchMemoryDisplay (int nArgs=0); + Update_t _SearchMemoryDisplay (int nArgs=0); // TODO: CLEANUP // Update_t CmdMemorySearchLowBit (int nArgs); // Update_t CmdMemorySearchHiBit (int nArgs); Update_t CmdMemorySearchAscii (int nArgs); @@ -691,101 +693,100 @@ Update_t CmdOutputPrintf (int nArgs); Update_t CmdOutputRun (int nArgs); // Registers - Update_t CmdRegisterSet (int nArgs); + Update_t CmdRegisterSet (int nArgs); // Source Level Debugging - Update_t CmdSource (int nArgs); - Update_t CmdSync (int nArgs); + Update_t CmdSource (int nArgs); + Update_t CmdSync (int nArgs); // Stack - Update_t CmdStackPush (int nArgs); - Update_t CmdStackPop (int nArgs); - Update_t CmdStackPopPseudo (int nArgs); - Update_t CmdStackReturn (int nArgs); + Update_t CmdStackPush (int nArgs); + Update_t CmdStackPop (int nArgs); + Update_t CmdStackPopPseudo (int nArgs); + Update_t CmdStackReturn (int nArgs); // Symbols - Update_t CmdSymbols (int nArgs); - Update_t CmdSymbolsClear (int nArgs); - Update_t CmdSymbolsList (int nArgs); - Update_t CmdSymbolsLoad (int nArgs); - Update_t CmdSymbolsInfo (int nArgs); - Update_t CmdSymbolsSave (int nArgs); + Update_t CmdSymbols (int nArgs); + Update_t CmdSymbolsClear (int nArgs); + Update_t CmdSymbolsList (int nArgs); + Update_t CmdSymbolsLoad (int nArgs); + Update_t CmdSymbolsInfo (int nArgs); + Update_t CmdSymbolsSave (int nArgs); - Update_t CmdSymbolsCommand (int nArgs); -// Update_t CmdSymbolsMain (int nArgs); -// Update_t CmdSymbolsBasic (int nArgs); -// Update_t CmdSymbolsUser (int nArgs); -// Update_t CmdSymbolsAssembly (int nArgs); -// Update_t CmdSymbolsSource (int nArgs); + Update_t CmdSymbolsCommand (int nArgs); +// Update_t CmdSymbolsMain (int nArgs); +// Update_t CmdSymbolsBasic (int nArgs); +// Update_t CmdSymbolsUser (int nArgs); +// Update_t CmdSymbolsAssembly (int nArgs); +// Update_t CmdSymbolsSource (int nArgs); - // View - Update_t CmdViewOutput_Text4X (int nArgs); - Update_t CmdViewOutput_Text41 (int nArgs); - Update_t CmdViewOutput_Text42 (int nArgs); - Update_t CmdViewOutput_Text8X (int nArgs); - Update_t CmdViewOutput_Text81 (int nArgs); - Update_t CmdViewOutput_Text82 (int nArgs); +// View + Update_t CmdViewOutput_Text4X (int nArgs); + Update_t CmdViewOutput_Text41 (int nArgs); + Update_t CmdViewOutput_Text42 (int nArgs); + Update_t CmdViewOutput_Text8X (int nArgs); + Update_t CmdViewOutput_Text81 (int nArgs); + Update_t CmdViewOutput_Text82 (int nArgs); - Update_t CmdViewOutput_GRX (int nArgs); - Update_t CmdViewOutput_GR1 (int nArgs); - Update_t CmdViewOutput_GR2 (int nArgs); - Update_t CmdViewOutput_DGRX (int nArgs); - Update_t CmdViewOutput_DGR1 (int nArgs); - Update_t CmdViewOutput_DGR2 (int nArgs); + Update_t CmdViewOutput_GRX (int nArgs); + Update_t CmdViewOutput_GR1 (int nArgs); + Update_t CmdViewOutput_GR2 (int nArgs); + Update_t CmdViewOutput_DGRX (int nArgs); + Update_t CmdViewOutput_DGR1 (int nArgs); + Update_t CmdViewOutput_DGR2 (int nArgs); - Update_t CmdViewOutput_HGRX (int nArgs); - Update_t CmdViewOutput_HGR1 (int nArgs); - Update_t CmdViewOutput_HGR2 (int nArgs); - Update_t CmdViewOutput_DHGRX (int nArgs); - Update_t CmdViewOutput_DHGR1 (int nArgs); - Update_t CmdViewOutput_DHGR2 (int nArgs); + Update_t CmdViewOutput_HGRX (int nArgs); + Update_t CmdViewOutput_HGR1 (int nArgs); + Update_t CmdViewOutput_HGR2 (int nArgs); + Update_t CmdViewOutput_DHGRX (int nArgs); + Update_t CmdViewOutput_DHGR1 (int nArgs); + Update_t CmdViewOutput_DHGR2 (int nArgs); // Watch - Update_t CmdWatch (int nArgs); - Update_t CmdWatchAdd (int nArgs); - Update_t CmdWatchClear (int nArgs); - Update_t CmdWatchDisable (int nArgs); - Update_t CmdWatchEnable (int nArgs); - Update_t CmdWatchList (int nArgs); -// Update_t CmdWatchLoad (int nArgs); - Update_t CmdWatchSave (int nArgs); + Update_t CmdWatch (int nArgs); + Update_t CmdWatchAdd (int nArgs); + Update_t CmdWatchClear (int nArgs); + Update_t CmdWatchDisable (int nArgs); + Update_t CmdWatchEnable (int nArgs); + Update_t CmdWatchList (int nArgs); +// Update_t CmdWatchLoad (int nArgs); + Update_t CmdWatchSave (int nArgs); // Window - Update_t CmdWindow (int nArgs); - Update_t CmdWindowCycleNext (int nArgs); - Update_t CmdWindowCyclePrev (int nArgs); - Update_t CmdWindowLast (int nArgs); + Update_t CmdWindow (int nArgs); + Update_t CmdWindowCycleNext (int nArgs); + Update_t CmdWindowCyclePrev (int nArgs); + Update_t CmdWindowLast (int nArgs); - Update_t CmdWindowShowCode (int nArgs); - Update_t CmdWindowShowCode1 (int nArgs); - Update_t CmdWindowShowCode2 (int nArgs); - Update_t CmdWindowShowData (int nArgs); - Update_t CmdWindowShowData1 (int nArgs); - Update_t CmdWindowShowData2 (int nArgs); - Update_t CmdWindowShowSymbols1(int nArgs); - Update_t CmdWindowShowSymbols2(int nArgs); - Update_t CmdWindowShowSource (int nArgs); - Update_t CmdWindowShowSource1 (int nArgs); - Update_t CmdWindowShowSource2 (int nArgs); + Update_t CmdWindowShowCode (int nArgs); + Update_t CmdWindowShowCode1 (int nArgs); + Update_t CmdWindowShowCode2 (int nArgs); + Update_t CmdWindowShowData (int nArgs); + Update_t CmdWindowShowData1 (int nArgs); + Update_t CmdWindowShowData2 (int nArgs); + Update_t CmdWindowShowSymbols1 (int nArgs); + Update_t CmdWindowShowSymbols2 (int nArgs); + Update_t CmdWindowShowSource (int nArgs); + Update_t CmdWindowShowSource1 (int nArgs); + Update_t CmdWindowShowSource2 (int nArgs); - Update_t CmdWindowViewCode (int nArgs); - Update_t CmdWindowViewConsole (int nArgs); - Update_t CmdWindowViewData (int nArgs); - Update_t CmdWindowViewOutput (int nArgs); - Update_t CmdWindowViewSource (int nArgs); - Update_t CmdWindowViewSymbols (int nArgs); + Update_t CmdWindowViewCode (int nArgs); + Update_t CmdWindowViewConsole (int nArgs); + Update_t CmdWindowViewData (int nArgs); + Update_t CmdWindowViewOutput (int nArgs); + Update_t CmdWindowViewSource (int nArgs); + Update_t CmdWindowViewSymbols (int nArgs); - Update_t CmdWindowWidthToggle (int nArgs); - -// Update_t CmdZeroPageShow (int nArgs); -// Update_t CmdZeroPageHide (int nArgs); -// Update_t CmdZeroPageToggle (int nArgs); + Update_t CmdWindowWidthToggle (int nArgs); // ZeroPage - Update_t CmdZeroPage (int nArgs); - Update_t CmdZeroPageAdd (int nArgs); - Update_t CmdZeroPageClear (int nArgs); - Update_t CmdZeroPageDisable (int nArgs); - Update_t CmdZeroPageEnable (int nArgs); - Update_t CmdZeroPageList (int nArgs); -// Update_t CmdZeroPageLoad (int nArgs); - Update_t CmdZeroPageSave (int nArgs); - Update_t CmdZeroPagePointer (int nArgs); +// Update_t CmdZeroPageShow (int nArgs); +// Update_t CmdZeroPageHide (int nArgs); +// Update_t CmdZeroPageToggle (int nArgs); + Update_t CmdZeroPage (int nArgs); + Update_t CmdZeroPageAdd (int nArgs); + Update_t CmdZeroPageClear (int nArgs); + Update_t CmdZeroPageDisable (int nArgs); + Update_t CmdZeroPageEnable (int nArgs); + Update_t CmdZeroPageList (int nArgs); +// Update_t CmdZeroPageLoad (int nArgs); + Update_t CmdZeroPageSave (int nArgs); + Update_t CmdZeroPagePointer (int nArgs); // Cursor _________________________________________________________________________________________ diff --git a/source/Video.cpp b/source/Video.cpp index 6ccb0770..d11b41e0 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1063,7 +1063,8 @@ void VideoDisplayLogo () SelectObject(hFrameDC,font); // sprintf( szVersion, "NTSC Alpha v14 HorzClock" ); - sprintf( szVersion, "NTSC Alpha v15 Fraps" ); +// sprintf( szVersion, "NTSC Alpha v15 Fraps" ); + sprintf( szVersion, "NTSC Alpha v16 Palette" ); xoff = -g_nViewportCX + g_nViewportCX/6; yoff = +g_nViewportCY/16; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); From a9450e196d4568ae604a26b3150c0044be1a0279 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 09:27:28 -0800 Subject: [PATCH 077/121] DOC: Added: 'ntsc' debugger command --- docs/Debugger_Changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/Debugger_Changelog.txt b/docs/Debugger_Changelog.txt index 600bc3a2..57a0e777 100644 --- a/docs/Debugger_Changelog.txt +++ b/docs/Debugger_Changelog.txt @@ -1,4 +1,11 @@ /* + +2.9.0.0 Added: ntsc save [filename], ntsc load [filename], to save/load the NTSC palette. + Default filename is "AppleWinNTSC4096x4@32.data" + To load this file in GIMP: Open, Select File Type: "Raw image data", Raw image data (*.data), RGB Alpha, Width: 4096, Height: 4 + to save this file in GIMP: Open, Export To, Select File Type (By Extension) Raw image data, RGB Type: Standard (R,G,B) + + .8 Fixed: Showing/hiding the address and/or opcodes will show long symbolic targets without overflowing into the register info pane Bug #227 .7 Fixed: ASC #:# with string containing null byte wouldn't show rest of string .6 Added: Print-Screen when in debugger will copy the debugger window as text From 2a54240372e4e63ad95fcbdce66443393355f9c9 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 09:28:23 -0800 Subject: [PATCH 078/121] Fix: force ntsc export alpha=255 --- source/Debugger/Debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index a9296ae5..b724fa96 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4939,8 +4939,8 @@ Update_t CmdNTSC (int nArgs) *pDst++ = pSrc[2]; *pDst++ = pSrc[1]; *pDst++ = pSrc[0]; - *pDst++ = pSrc[3]; - +// *pDst++ = pSrc[3]; + *pDst++ = 0xFF; // Force A=1, 100% opacity pSrc += 4; } } From fdd1d73ba623c428d7bfff9d358949f2da4b2658 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 09:30:08 -0800 Subject: [PATCH 079/121] Add .bmp to the project grouping --- ApplewinExpress10.00.vcxproj | 7 +++++++ ApplewinExpress10.00.vcxproj.filters | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/ApplewinExpress10.00.vcxproj b/ApplewinExpress10.00.vcxproj index eb54c1df..c763e41b 100644 --- a/ApplewinExpress10.00.vcxproj +++ b/ApplewinExpress10.00.vcxproj @@ -463,6 +463,13 @@ + + + + + + + diff --git a/ApplewinExpress10.00.vcxproj.filters b/ApplewinExpress10.00.vcxproj.filters index 69cbe148..023cd320 100644 --- a/ApplewinExpress10.00.vcxproj.filters +++ b/ApplewinExpress10.00.vcxproj.filters @@ -612,6 +612,16 @@ Resources + + Resources + + + + + + + + From ec6f124140ddc027a3d68a9f35409d96374b0d5b Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 11:22:41 -0800 Subject: [PATCH 080/121] WIP: fix 560x384 screenshots (600x420 for the time being) --- source/Video.cpp | 106 +++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index d11b41e0..0af7c079 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1561,46 +1561,41 @@ void Video_TakeScreenShot( int iScreenShotType ) g_nLastScreenShot++; } - -typedef char int8; -typedef short int16; -typedef int int32; -typedef unsigned char u8; -typedef signed short s16; - -/// turn of MSVC struct member padding -#pragma pack(push,1) +#ifdef _MSC_VER + /// turn of MSVC struct member padding + #pragma pack(push,1) +#endif struct bgra_t { - u8 b; - u8 g; - u8 r; - u8 a; // reserved on Win32 + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; // reserved on Win32 }; struct WinBmpHeader_t { // BITMAPFILEHEADER // Addr Size - char nCookie[2] ; // 0x00 0x02 BM - int32 nSizeFile ; // 0x02 0x04 0 = ignore - int16 nReserved1 ; // 0x06 0x02 - int16 nReserved2 ; // 0x08 0x02 - int32 nOffsetData ; // 0x0A 0x04 + uint8_t nCookie[2] ; // 0x00 0x02 BM + uint32_t nSizeFile ; // 0x02 0x04 0 = ignore + uint16_t nReserved1 ; // 0x06 0x02 + uint16_t nReserved2 ; // 0x08 0x02 + uint32_t nOffsetData ; // 0x0A 0x04 // == 0x0D (14) // BITMAPINFOHEADER - int32 nStructSize ; // 0x0E 0x04 biSize - int32 nWidthPixels ; // 0x12 0x04 biWidth - int32 nHeightPixels ; // 0x16 0x04 biHeight - int16 nPlanes ; // 0x1A 0x02 biPlanes - int16 nBitsPerPixel ; // 0x1C 0x02 biBitCount - int32 nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB - int32 nSizeImage ; // 0x22 0x04 0 = ignore - int32 nXPelsPerMeter ; // 0x26 0x04 - int32 nYPelsPerMeter ; // 0x2A 0x04 - int32 nPaletteColors ; // 0x2E 0x04 - int32 nImportantColors; // 0x32 0x04 + uint32_t nStructSize ; // 0x0E 0x04 biSize + uint32_t nWidthPixels ; // 0x12 0x04 biWidth + uint32_t nHeightPixels ; // 0x16 0x04 biHeight + uint16_t nPlanes ; // 0x1A 0x02 biPlanes + uint16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount + uint32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB + uint32_t nSizeImage ; // 0x22 0x04 0 = ignore + uint32_t nXPelsPerMeter ; // 0x26 0x04 + uint32_t nYPelsPerMeter ; // 0x2A 0x04 + uint32_t nPaletteColors ; // 0x2E 0x04 + uint32_t nImportantColors; // 0x32 0x04 // == 0x28 (40) // RGBQUAD @@ -1644,22 +1639,30 @@ WinBmpHeader_t g_tBmpHeader; void Video_MakeScreenShot(FILE *pFile) { #if SCREENSHOT_BMP - g_tBmpHeader.nCookie[ 0 ] = 'B'; // 0x42 - g_tBmpHeader.nCookie[ 1 ] = 'M'; // 0x4d - g_tBmpHeader.nSizeFile = 0; - g_tBmpHeader.nReserved1 = 0; - g_tBmpHeader.nReserved2 = 0; - g_tBmpHeader.nOffsetData = sizeof(WinBmpHeader_t) + (256 * sizeof(bgra_t)); - g_tBmpHeader.nStructSize = 0x28; // sizeof( WinBmpHeader_t ); - g_tBmpHeader.nWidthPixels = g_iScreenshotType ? FRAMEBUFFER_W/2 :FRAMEBUFFER_W; - g_tBmpHeader.nHeightPixels = g_iScreenshotType ? FRAMEBUFFER_H/2 : FRAMEBUFFER_H; - g_tBmpHeader.nPlanes = 1; - g_tBmpHeader.nBitsPerPixel = 8; - g_tBmpHeader.nCompression = BI_RGB; - g_tBmpHeader.nSizeImage = 0; - g_tBmpHeader.nXPelsPerMeter = 0; - g_tBmpHeader.nYPelsPerMeter = 0; - g_tBmpHeader.nPaletteColors = 256; + g_tBmpHeader.nCookie[ 0 ] = 'B'; // 0x42 + g_tBmpHeader.nCookie[ 1 ] = 'M'; // 0x4d + g_tBmpHeader.nSizeFile = 0; + g_tBmpHeader.nReserved1 = 0; + g_tBmpHeader.nReserved2 = 0; + g_tBmpHeader.nOffsetData = sizeof(WinBmpHeader_t) + (256 * sizeof(bgra_t)); + g_tBmpHeader.nStructSize = 0x28; // sizeof( WinBmpHeader_t ); + g_tBmpHeader.nWidthPixels = g_iScreenshotType ? FRAMEBUFFER_W/2 :FRAMEBUFFER_W; + g_tBmpHeader.nHeightPixels = g_iScreenshotType ? FRAMEBUFFER_H/2 : FRAMEBUFFER_H; + g_tBmpHeader.nPlanes = 1; +#if VIDEO_SCREENSHOT_PALETTE + g_tBmpHeader.nBitsPerPixel = 8; +#else + g_tBmpHeader.nBitsPerPixel = 32; +#endif + g_tBmpHeader.nCompression = BI_RGB; // none + g_tBmpHeader.nSizeImage = 0; + g_tBmpHeader.nXPelsPerMeter = 0; + g_tBmpHeader.nYPelsPerMeter = 0; +#if VIDEO_SCREENSHOT_PALETTE + g_tBmpHeader.nPaletteColors = 256; +#else + g_tBmpHeader.nPaletteColors = 0; +#endif g_tBmpHeader.nImportantColors = 0; // char sText[256]; @@ -1675,24 +1678,27 @@ void Video_MakeScreenShot(FILE *pFile) int nLen; fwrite( &g_tBmpHeader, sizeof( g_tBmpHeader ), 1, pFile ); + uint32_t *pSrc; +#if VIDEO_SCREENSHOT_PALETTE // Write Palette Data - u8 *pSrc = ((u8*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER); + pSrc = ((uint8_t*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER); nLen = g_tBmpHeader.nPaletteColors * sizeof(bgra_t); // RGBQUAD fwrite( pSrc, nLen, 1, pFile ); pSrc += nLen; +#endif // Write Pixel Data // No need to use GetDibBits() since we already have http://msdn.microsoft.com/en-us/library/ms532334.aspx // @reference: "Storing an Image" http://msdn.microsoft.com/en-us/library/ms532340(VS.85).aspx - pSrc = ((uint8_t*)g_pFramebufferbits); - nLen = g_tBmpHeader.nWidthPixels * g_tBmpHeader.nHeightPixels * g_tBmpHeader.nBitsPerPixel / 8; + pSrc = (uint32_t*) g_pFramebufferbits; + nLen = (g_tBmpHeader.nWidthPixels * g_tBmpHeader.nHeightPixels * g_tBmpHeader.nBitsPerPixel) / 8; if( g_iScreenshotType == SCREENSHOT_280x192 ) { pSrc += FRAMEBUFFER_W; // Start on odd scanline (otherwise for 50% scanline mode get an all black image!) - u8 aScanLine[ 280 ]; - u8 *pDst; + uint32_t aScanLine[ 280 ]; + uint32_t *pDst; // 50% Half Scan Line clears every odd scanline. // SHIFT+PrintScreen saves only the even rows. From 8876044d3a50c78921f8d869e27a99f5b889c33b Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 11:23:46 -0800 Subject: [PATCH 081/121] Fixed debugger ntsc save .bmp to save as 64x256 raw image --- source/Debugger/Debug.cpp | 134 ++++++++++++++++++++++++++++++++------ 1 file changed, 115 insertions(+), 19 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index b724fa96..59a5b9fa 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4876,7 +4876,15 @@ Update_t CmdNTSC (int nArgs) char *pExtension; }; - const KnownFileType_t aFileTypes[] = + enum KnownFileType_e + { + TYPE_UNKNOWN + ,TYPE_BMP + ,TYPE_RAW + ,NUM_FILE_TYPES + }; + + const KnownFileType_t aFileTypes[ NUM_FILE_TYPES ] = { { "" } // n/a ,{ ".bmp" } @@ -4884,8 +4892,13 @@ Update_t CmdNTSC (int nArgs) // ,{ ".raw" } // ,{ ".ntsc" } }; - const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t ); + const int nFileType = sizeof( aFileTypes ) / sizeof( KnownFileType_t ); const KnownFileType_t *pFileType = NULL; + /* */ KnownFileType_e iFileType = TYPE_UNKNOWN; + +#if _DEBUG + assert( (nFileType == NUM_FILE_TYPES) ); +#endif char *pFileName = (nArgs > 1) ? g_aArgs[ 2 ].sArg : ""; int nLen = strlen( pFileName ); @@ -4894,11 +4907,12 @@ Update_t CmdNTSC (int nArgs) { if( *pEnd == '.' ) { - for( int i = 1; i < nFileTypes; i++ ) + for( int i = TYPE_BMP; i < NUM_FILE_TYPES; i++ ) { if( strcmp( pEnd, aFileTypes[i].pExtension ) == 0 ) { pFileType = &aFileTypes[i]; + iFileType = (KnownFileType_e) i; break; } } @@ -4931,21 +4945,88 @@ Update_t CmdNTSC (int nArgs) class Swizzle32 { public: - static void swizzleRB( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) + static void swizzleRB( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly { const uint8_t* pEnd = pSrc + nSize; while ( pSrc < pEnd ) { - *pDst++ = pSrc[2]; - *pDst++ = pSrc[1]; - *pDst++ = pSrc[0]; -// *pDst++ = pSrc[3]; - *pDst++ = 0xFF; // Force A=1, 100% opacity + uint8_t r = pSrc[2]; + uint8_t g = pSrc[1]; + uint8_t b = pSrc[0]; + uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255 + + *pDst++ = r; + *pDst++ = g; + *pDst++ = b; + *pDst++ = a; pSrc += 4; } } }; + class Transpose4096x4to64x256 + { + public: + static void transpose( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) + { + /* + Source layout = 4096x4 @ 32-bit + +----+----+----+----+----+ + |BGRA|BGRA|BGRA|... |BGRA| phase 0 + +----+----+----+----+----+ + |BGRA|BGRA|BGRA|... |BGRA| phase 1 + +----+----+----+----+----| + |BGRA|BGRA|BGRA|... |BGRA| phase 2 + +----+----+----+----+----+ + |BGRA|BGRA|BGRA|... |BGRA| phase 3 + +----+----+----+----+----+ + 0 1 2 4095 column + + Destination layout = 16x1024 @ 32-bit + | phase 0 | phase 1 | phase 2 | phase 3 | + +----+----+----+----+----+----+----+----+ + |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0 + +----+----+----+----+----+----+----+----+ + |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1 + +----+----+----+----+----+----+----+----+ + |... |... |... |... |... |... |... |... | + +----+----+----+----+----+----+----+----+ + |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1024 + +----+----+----+----+----+----+----+----+ + \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels + 64 byte + */ + + /* */ uint8_t *pTmp = pDst; + const uint32_t nBPP = 4; // bytes per pixel + + for( int iPhase = 0; iPhase < 4; iPhase++ ) + { + pDst = pTmp + (iPhase * 16 * nBPP); + + for( int x = 0; x < 4096/16; x++ ) // 4096px/16 px = 256 columns + { + for( int i = 0; i < 16*nBPP; i++ ) // 16 px, 32-bit + *pDst++ = *pSrc++; + + pDst -= (16*nBPP); + pDst += (64*nBPP); // move to next scan line + } + } + +/* + for( int nPhase = 0; nPhase < 4; nPhase++ ) + { + for( int x = 0; x < 1024; x++ ) + for( int y = 0; y < 4; y+= ) + { + pSrc = pBeg + (nPhase * 4) + } + } +*/ + } + }; + uint32_t* pChromaTable = NTSC_VideoGetChromaTable( false, false ); if (nFound) @@ -4962,18 +5043,28 @@ Update_t CmdNTSC (int nArgs) if( pFile ) { size_t nWrote = 0; + uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; // Write BMP + if( iFileType == TYPE_BMP ) + { // need to save 32-bit bpp as 24-bit bpp // VideoSaveScreenShot() + Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + Transpose4096x4to64x256::transpose( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + + // Write BMP header + + } + else + { + // Write RAW + Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + } - // Write RAW - uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; - Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); nWrote = fwrite( pSwizzled, g_nChromaSize, 1, pFile ); - - delete [] pSwizzled; fclose( pFile ); + delete [] pSwizzled; if (nWrote == 1) { @@ -4996,6 +5087,7 @@ Update_t CmdNTSC (int nArgs) { // Get File Size size_t nFileSize = _GetFileSize( pFile ); + uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; if( nFileSize != g_nChromaSize ) { @@ -5003,14 +5095,18 @@ Update_t CmdNTSC (int nArgs) return ConsoleUpdate(); } - // BMP - // RAW - uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; size_t nRead = fread( pSwizzled, g_nChromaSize, 1, pFile ); - Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); + if( iFileType == TYPE_BMP ) + { + } + else // RAW + { + Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); + } + + fclose( pFile ); delete [] pSwizzled; - fclose( pFile ); ConsoleFilename::update( "Loaded" ); } From 0103d43f3aee74f535327ba5f4eb52d3a0911b66 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 11:24:27 -0800 Subject: [PATCH 082/121] Added debug option for alt NTSC 512x4 table --- source/NTSC.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 39a77d49..6c9af47c 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -30,6 +30,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NTSC.h" #include "NTSC_CharSet.cpp" +#define ALT_TABLE 0 +#if ALT_TABLE + #include "ntsc_rgb.h" +#endif + //LPBYTE MemGetMainPtr(const WORD); //LPBYTE MemGetBankPtr(const UINT nBank); @@ -1408,6 +1413,10 @@ uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeCol if( bMonitorTypeColorTV ) return (uint32_t*) g_aHueColorTV; else +#if ALT_TABLE + g_nChromaSize = sizeof(T_NTSC); + return (uint32_t*)T_NTSC; +#endif return (uint32_t*) g_aHueMonitor; } } From fcd9d7377b03f968cd49f5a5d1ed1ec911697ed2 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 11:42:53 -0800 Subject: [PATCH 083/121] Fixed screenshots (large), factored out Windows BMP Header Struct --- source/Video.cpp | 116 ++++++++++++++++++----------------------------- source/Video.h | 50 ++++++++++++++++++++ 2 files changed, 95 insertions(+), 71 deletions(-) diff --git a/source/Video.cpp b/source/Video.cpp index 0af7c079..abf773b2 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1561,48 +1561,6 @@ void Video_TakeScreenShot( int iScreenShotType ) g_nLastScreenShot++; } -#ifdef _MSC_VER - /// turn of MSVC struct member padding - #pragma pack(push,1) -#endif - -struct bgra_t -{ - uint8_t b; - uint8_t g; - uint8_t r; - uint8_t a; // reserved on Win32 -}; - -struct WinBmpHeader_t -{ - // BITMAPFILEHEADER // Addr Size - uint8_t nCookie[2] ; // 0x00 0x02 BM - uint32_t nSizeFile ; // 0x02 0x04 0 = ignore - uint16_t nReserved1 ; // 0x06 0x02 - uint16_t nReserved2 ; // 0x08 0x02 - uint32_t nOffsetData ; // 0x0A 0x04 - // == 0x0D (14) - - // BITMAPINFOHEADER - uint32_t nStructSize ; // 0x0E 0x04 biSize - uint32_t nWidthPixels ; // 0x12 0x04 biWidth - uint32_t nHeightPixels ; // 0x16 0x04 biHeight - uint16_t nPlanes ; // 0x1A 0x02 biPlanes - uint16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount - uint32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB - uint32_t nSizeImage ; // 0x22 0x04 0 = ignore - uint32_t nXPelsPerMeter ; // 0x26 0x04 - uint32_t nYPelsPerMeter ; // 0x2A 0x04 - uint32_t nPaletteColors ; // 0x2E 0x04 - uint32_t nImportantColors; // 0x32 0x04 - // == 0x28 (40) - - // RGBQUAD - // pixelmap -}; -#pragma pack(pop) - WinBmpHeader_t g_tBmpHeader; #if SCREENSHOT_TGA @@ -1635,35 +1593,51 @@ WinBmpHeader_t g_tBmpHeader; TargaHeader_t g_tTargaHeader; #endif // SCREENSHOT_TGA +void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel ) +{ +#if SCREENSHOT_BMP + pBmp->nCookie[ 0 ] = 'B'; // 0x42 + pBmp->nCookie[ 1 ] = 'M'; // 0x4d + pBmp->nSizeFile = 0; + pBmp->nReserved1 = 0; + pBmp->nReserved2 = 0; +#if VIDEO_SCREENSHOT_PALETTE + pBmp->nOffsetData = sizeof(WinBmpHeader_t) + (256 * sizeof(bgra_t)); +#else + pBmp->nOffsetData = sizeof(WinBmpHeader_t); +#endif + pBmp->nStructSize = 0x28; // sizeof( WinBmpHeader_t ); + pBmp->nWidthPixels = nWidth; + pBmp->nHeightPixels = nHeight; + pBmp->nPlanes = 1; +#if VIDEO_SCREENSHOT_PALETTE + pBmp->nBitsPerPixel = 8; +#else + pBmp->nBitsPerPixel = nBitsPerPixel; +#endif + pBmp->nCompression = BI_RGB; // none + pBmp->nSizeImage = 0; + pBmp->nXPelsPerMeter = 0; + pBmp->nYPelsPerMeter = 0; +#if VIDEO_SCREENSHOT_PALETTE + pBmp->nPaletteColors = 256; +#else + pBmp->nPaletteColors = 0; +#endif + pBmp->nImportantColors = 0; +} + //=========================================================================== void Video_MakeScreenShot(FILE *pFile) { -#if SCREENSHOT_BMP - g_tBmpHeader.nCookie[ 0 ] = 'B'; // 0x42 - g_tBmpHeader.nCookie[ 1 ] = 'M'; // 0x4d - g_tBmpHeader.nSizeFile = 0; - g_tBmpHeader.nReserved1 = 0; - g_tBmpHeader.nReserved2 = 0; - g_tBmpHeader.nOffsetData = sizeof(WinBmpHeader_t) + (256 * sizeof(bgra_t)); - g_tBmpHeader.nStructSize = 0x28; // sizeof( WinBmpHeader_t ); - g_tBmpHeader.nWidthPixels = g_iScreenshotType ? FRAMEBUFFER_W/2 :FRAMEBUFFER_W; - g_tBmpHeader.nHeightPixels = g_iScreenshotType ? FRAMEBUFFER_H/2 : FRAMEBUFFER_H; - g_tBmpHeader.nPlanes = 1; -#if VIDEO_SCREENSHOT_PALETTE - g_tBmpHeader.nBitsPerPixel = 8; -#else - g_tBmpHeader.nBitsPerPixel = 32; -#endif - g_tBmpHeader.nCompression = BI_RGB; // none - g_tBmpHeader.nSizeImage = 0; - g_tBmpHeader.nXPelsPerMeter = 0; - g_tBmpHeader.nYPelsPerMeter = 0; -#if VIDEO_SCREENSHOT_PALETTE - g_tBmpHeader.nPaletteColors = 256; -#else - g_tBmpHeader.nPaletteColors = 0; -#endif - g_tBmpHeader.nImportantColors = 0; + WinBmpHeader_t *pBmp = &g_tBmpHeader; + + Video_SetBitmapHeader( + pBmp, + g_iScreenshotType ? FRAMEBUFFER_W/2 :FRAMEBUFFER_W, + g_iScreenshotType ? FRAMEBUFFER_H/2 : FRAMEBUFFER_H, + 32 + ); // char sText[256]; // sprintf( sText, "sizeof: BITMAPFILEHEADER = %d\n", sizeof(BITMAPFILEHEADER) ); // = 14 @@ -1671,12 +1645,12 @@ void Video_MakeScreenShot(FILE *pFile) // sprintf( sText, "sizeof: BITMAPINFOHEADER = %d\n", sizeof(BITMAPINFOHEADER) ); // = 40 // MessageBox( g_hFrameWindow, sText, "Info 2", MB_OK ); - char sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize[ sizeof( WinBmpHeader_t ) == (14 + 40) ]; - sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize; + char sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[ sizeof( WinBmpHeader_t ) == (14 + 40) ]; + /**/ sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[0]=0; // Write Header int nLen; - fwrite( &g_tBmpHeader, sizeof( g_tBmpHeader ), 1, pFile ); + fwrite( pBmp, sizeof( WinBmpHeader_t ), 1, pFile ); uint32_t *pSrc; #if VIDEO_SCREENSHOT_PALETTE diff --git a/source/Video.h b/source/Video.h index 142e4314..25f96eb0 100644 --- a/source/Video.h +++ b/source/Video.h @@ -53,6 +53,54 @@ APPLE_FONT_Y_APPLE_40COL = 512, // ][ }; +#ifdef _MSC_VER + /// turn of MSVC struct member padding + #pragma pack(push,1) + #define PACKED +#else + #define PACKED // TODO: FIXME: gcc/clang __attribute__ +#endif + +struct bgra_t +{ + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; // reserved on Win32 +}; + +struct WinBmpHeader_t +{ + // BITMAPFILEHEADER // Addr Size + uint8_t nCookie[2] ; // 0x00 0x02 BM + uint32_t nSizeFile ; // 0x02 0x04 0 = ignore + uint16_t nReserved1 ; // 0x06 0x02 + uint16_t nReserved2 ; // 0x08 0x02 + uint32_t nOffsetData ; // 0x0A 0x04 + // == 0x0D (14) + + // BITMAPINFOHEADER + uint32_t nStructSize ; // 0x0E 0x04 biSize + uint32_t nWidthPixels ; // 0x12 0x04 biWidth + uint32_t nHeightPixels ; // 0x16 0x04 biHeight + uint16_t nPlanes ; // 0x1A 0x02 biPlanes + uint16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount + uint32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB + uint32_t nSizeImage ; // 0x22 0x04 0 = ignore + uint32_t nXPelsPerMeter ; // 0x26 0x04 + uint32_t nYPelsPerMeter ; // 0x2A 0x04 + uint32_t nPaletteColors ; // 0x2E 0x04 + uint32_t nImportantColors; // 0x32 0x04 + // == 0x28 (40) + + // RGBQUAD + // pixelmap +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + // Globals __________________________________________________________ extern HBITMAP g_hLogoBitmap; @@ -113,6 +161,8 @@ enum VideoScreenShot_e SCREENSHOT_280x192 }; void Video_TakeScreenShot( int iScreenShotType ); +void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel ); + // Win32/MSVC: __stdcall BYTE VideoCheckMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); From c286f7fc991c1a7ae55deb62c13062a5a2d979fe Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 11:43:51 -0800 Subject: [PATCH 084/121] Removed bgra_t struct since now in Video.h --- source/NTSC.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 6c9af47c..06f04914 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -30,6 +30,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NTSC.h" #include "NTSC_CharSet.cpp" +#define NTSC_REMOVE_WHITE_RING 1 // 0 = theoritical dimmed white, 1 = practical pure white + #define ALT_TABLE 0 #if ALT_TABLE #include "ntsc_rgb.h" @@ -90,14 +92,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA float y, i, q; }; - struct bgra_t - { - uint8_t b; - uint8_t g; - uint8_t r; - uint8_t a; - }; - struct rgba_t { uint8_t r; @@ -894,11 +888,11 @@ static void initChromaPhaseTables (void) r64 = y0 + (I_TO_R * i) + (Q_TO_R * q); g64 = y0 + (I_TO_G * i) + (Q_TO_G * q); b64 = y0 + (I_TO_B * i) + (Q_TO_B * q); - +#if NTSC_REMOVE_WHITE_RING // Remove white ringing if(brightness > 0.9f) b64 = g64 = r64 = 1.0; - +#endif b32 = clampZeroOne( (float)b64); g32 = clampZeroOne( (float)g64); r32 = clampZeroOne( (float)r64); From 9ffc6b749114ef95754fd523797fc7c686826efe Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 12:14:38 -0800 Subject: [PATCH 085/121] Clean ntsc export bmp, WIP: import bmp --- source/Debugger/Debug.cpp | 116 +++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 59a5b9fa..28316420 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4964,38 +4964,38 @@ Update_t CmdNTSC (int nArgs) } }; - class Transpose4096x4to64x256 + class Transpose4096x4 { public: - static void transpose( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) + static void transposeTo64x256( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) { - /* - Source layout = 4096x4 @ 32-bit - +----+----+----+----+----+ - |BGRA|BGRA|BGRA|... |BGRA| phase 0 - +----+----+----+----+----+ - |BGRA|BGRA|BGRA|... |BGRA| phase 1 - +----+----+----+----+----| - |BGRA|BGRA|BGRA|... |BGRA| phase 2 - +----+----+----+----+----+ - |BGRA|BGRA|BGRA|... |BGRA| phase 3 - +----+----+----+----+----+ - 0 1 2 4095 column + /* + Source layout = 4096x4 @ 32-bit + +----+----+----+----+----+ + |BGRA|BGRA|BGRA|... |BGRA| phase 0 + +----+----+----+----+----+ + |BGRA|BGRA|BGRA|... |BGRA| phase 1 + +----+----+----+----+----| + |BGRA|BGRA|BGRA|... |BGRA| phase 2 + +----+----+----+----+----+ + |BGRA|BGRA|BGRA|... |BGRA| phase 3 + +----+----+----+----+----+ + 0 1 2 4095 column - Destination layout = 16x1024 @ 32-bit - | phase 0 | phase 1 | phase 2 | phase 3 | - +----+----+----+----+----+----+----+----+ - |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0 - +----+----+----+----+----+----+----+----+ - |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1 - +----+----+----+----+----+----+----+----+ - |... |... |... |... |... |... |... |... | - +----+----+----+----+----+----+----+----+ - |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1024 - +----+----+----+----+----+----+----+----+ - \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels - 64 byte - */ + Destination layout = 16x1024 @ 32-bit + | phase 0 | phase 1 | phase 2 | phase 3 | + +----+----+----+----+----+----+----+----+ + |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0 + +----+----+----+----+----+----+----+----+ + |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1 + +----+----+----+----+----+----+----+----+ + |... |... |... |... |... |... |... |... | + +----+----+----+----+----+----+----+----+ + |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1024 + +----+----+----+----+----+----+----+----+ + \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels + 64 byte + */ /* */ uint8_t *pTmp = pDst; const uint32_t nBPP = 4; // bytes per pixel @@ -5013,17 +5013,16 @@ Update_t CmdNTSC (int nArgs) pDst += (64*nBPP); // move to next scan line } } + } -/* - for( int nPhase = 0; nPhase < 4; nPhase++ ) + static void transposeFrom64x256( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) + { + for( int iPhase = 0; iPhase < 4; iPhase++ ) + { + for( int y = 0; y < 256; y++ ) { - for( int x = 0; x < 1024; x++ ) - for( int y = 0; y < 4; y+= ) - { - pSrc = pBeg + (nPhase * 4) - } } -*/ + } } }; @@ -5045,20 +5044,21 @@ Update_t CmdNTSC (int nArgs) size_t nWrote = 0; uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; - // Write BMP if( iFileType == TYPE_BMP ) { // need to save 32-bit bpp as 24-bit bpp // VideoSaveScreenShot() - Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); - Transpose4096x4to64x256::transpose( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + Transpose4096x4::transposeTo64x256( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, pSwizzled ); // Note: Swizzle in-place! // Write BMP header - + WinBmpHeader_t bmp, *pBmp = &bmp; + Video_SetBitmapHeader( pBmp, 64, 256, 32 ); + fwrite( pBmp, sizeof( WinBmpHeader_t ), 1, pFile ); } else { - // Write RAW + // RAW has no header Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); } @@ -5082,9 +5082,13 @@ Update_t CmdNTSC (int nArgs) else if (iParam == PARAM_LOAD) { + char aStatusText[64] = "Loaded"; + FILE *pFile = fopen( sPaletteFilePath, "rb" ); if( pFile ) { + strcpy( aStatusText, "Loaded" ); + // Get File Size size_t nFileSize = _GetFileSize( pFile ); uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; @@ -5095,26 +5099,46 @@ Update_t CmdNTSC (int nArgs) return ConsoleUpdate(); } + if( iFileType == TYPE_BMP ) + { + WinBmpHeader_t bmp, *pBmp = &bmp; + fread( pBmp, sizeof( WinBmpHeader_t ), 1, pFile ); + fseek( pFile, pBmp->nOffsetData, SEEK_SET ); + + if( 0 + || (pBmp->nWidthPixels != 64 ) + || (pBmp->nHeightPixels != 256) + || (pBmp->nBitsPerPixel != 32 ) + || (pBmp->nOffsetData > nFileSize) + ) + { + strcpy( aStatusText, "Bitmap not 64x256@32" ); + goto _error; + } + } + size_t nRead = fread( pSwizzled, g_nChromaSize, 1, pFile ); if( iFileType == TYPE_BMP ) { + Transpose4096x4::transposeFrom64x256( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); + Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*)pChromaTable, (uint8_t*)pChromaTable ); // Note: Swizzle in-place! } else // RAW { Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); } - +_error: fclose( pFile ); delete [] pSwizzled; - - ConsoleFilename::update( "Loaded" ); } else { - ConsoleFilename::update( "File: " ); - ConsoleBufferPush( TEXT( "Error couldn't open file for reading." ) ); + strcpy( aStatusText, "File: " ); + ConsoleBufferPush( TEXT( "Error couldn't open file for reading." ) ); } + + ConsoleFilename::update( aStatusText ); } else return HelpLastCommand(); From 82fc84ccd2cded371699243b7ca37090431abcdd Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 16:56:47 -0800 Subject: [PATCH 086/121] Change SetCurrentImageDir() to return true/false --- source/Applewin.cpp | 7 +++++-- source/Applewin.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index debd4d47..76a0b3e6 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -545,7 +545,7 @@ void LoadConfiguration(void) //=========================================================================== -void SetCurrentImageDir(const char* pszImageDir) +bool SetCurrentImageDir(const char* pszImageDir) { strcpy(g_sCurrentDir, pszImageDir); @@ -556,7 +556,10 @@ void SetCurrentImageDir(const char* pszImageDir) g_sCurrentDir[ nLen + 1 ] = 0; } - SetCurrentDirectory(g_sCurrentDir); + if( SetCurrentDirectory(g_sCurrentDir) ) + return true; + + return false; } //=========================================================================== diff --git a/source/Applewin.h b/source/Applewin.h index 172bd308..24f19fd2 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -4,7 +4,7 @@ #include "Common.h" void SetCurrentCLK6502(); -void SetCurrentImageDir(const char* pszImageDir); +bool SetCurrentImageDir(const char* pszImageDir); extern char VERSIONSTRING[]; // Constructed in WinMain() From 9b2355fcfb6512e74dbc5f3107996966692dfa9e Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 22:45:56 -0800 Subject: [PATCH 087/121] Added Windows Bitmap v4 --- source/Video.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/source/Video.h b/source/Video.h index 25f96eb0..ab935426 100644 --- a/source/Video.h +++ b/source/Video.h @@ -97,6 +97,53 @@ struct WinBmpHeader_t // pixelmap }; +struct WinCIEXYZ +{ + uint32_t r; // fixed point 2.30 + uint32_t g; // fixed point 2.30 + uint32_t b; // fixed point 2.30 +}; + +struct WinBmpHeader4_t +{ + // BITMAPFILEHEADER // Addr Size + uint8_t nCookie[2] ; // 0x00 0x02 BM + uint32_t nSizeFile ; // 0x02 0x04 0 = ignore + uint16_t nReserved1 ; // 0x06 0x02 + uint16_t nReserved2 ; // 0x08 0x02 + uint32_t nOffsetData ; // 0x0A 0x04 + // ==== 0x0D (14) + + // BITMAPINFOHEADER + uint32_t nStructSize ; // 0x0E 0x04 biSize + uint32_t nWidthPixels ; // 0x12 0x04 biWidth + uint32_t nHeightPixels ; // 0x16 0x04 biHeight + uint16_t nPlanes ; // 0x1A 0x02 biPlanes + uint16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount + uint32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB + uint32_t nSizeImage ; // 0x22 0x04 0 = ignore + uint32_t nXPelsPerMeter ; // 0x26 0x04 + uint32_t nYPelsPerMeter ; // 0x2A 0x04 + uint32_t nPaletteColors ; // 0x2E 0x04 + uint32_t nImportantColors; // 0x32 0x04 + // ==== 0x28 (40) + + //BITMAPV4HEADER new fields + uint32_t nRedMask ; // 0x36 0x04 + uint32_t nGreenMask ; // 0x3A 0x04 + uint32_t nBlueMask ; // 0x3E 0x04 + uint32_t nAlphaMask ; // 0x42 0x04 + uint32_t nType ; // 0x46 0x04 + + uint32_t Rx, Ry, Rz ; // 0x4A 0x0C + uint32_t Gx, Gy, Gz ; // 0x56 0x0C + uint32_t Bx, By, Bz ; // 0x62 0x0C + + uint32_t nRedGamma ; // 0x6E 0x04 + uint32_t nGreenGamma ; // 0x72 0x04 + uint32_t nBlueGamma ; // 0x76 0x04 +}; + #ifdef _MSC_VER #pragma pack(pop) #endif From 4078afe82c6672c7da3a0f1fe1e701813e71efec Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 22:47:07 -0800 Subject: [PATCH 088/121] Reset chroma cycle back to 45 --- source/NTSC.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 06f04914..e11d4f0b 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NTSC_CharSet.cpp" #define NTSC_REMOVE_WHITE_RING 1 // 0 = theoritical dimmed white, 1 = practical pure white +#define DEBUG_PHASE_ZERO 0 #define ALT_TABLE 0 #if ALT_TABLE @@ -68,7 +69,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #if CHROMA_BLUR //#define CYCLESTART (PI/4.f) // PI/4 = 45 degrees - #define CYCLESTART (DEG_TO_RAD(33)) + #define CYCLESTART (DEG_TO_RAD(45)) #else // sharpness is higher, less color bleed #if CHROMA_FILTER == 2 #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = initFilterSignal(z); @@ -916,6 +917,15 @@ static void initChromaPhaseTables (void) g_aHueColorTV[phase][s].a = 255; } } + +#if DEBUG_PHASE_ZERO + uint8_t *p = (uint8_t*)g_aHueMonitor; + *p++ = 0xFF; + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0xFF; +#endif + } /* From ba1a08b96bcf3635a69dec53aa0ae4f5a5d8adc0 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 22:47:55 -0800 Subject: [PATCH 089/121] Add ntsc .bmp import --- source/Debugger/Debug.cpp | 182 ++++++++++++++++++++++++++------------ 1 file changed, 127 insertions(+), 55 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 28316420..6184bb1f 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4026,6 +4026,7 @@ Update_t CmdMemoryFill (int nArgs) static TCHAR g_sMemoryLoadSaveFileName[ MAX_PATH ] = TEXT(""); +// "PWD" //=========================================================================== Update_t CmdConfigGetDebugDir (int nArgs) { @@ -4036,6 +4037,7 @@ Update_t CmdConfigGetDebugDir (int nArgs) return ConsoleUpdate(); } +// "CD" //=========================================================================== Update_t CmdConfigSetDebugDir (int nArgs) { @@ -4945,64 +4947,101 @@ Update_t CmdNTSC (int nArgs) class Swizzle32 { public: - static void swizzleRB( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly + static void RGBAswapBGRA( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly { const uint8_t* pEnd = pSrc + nSize; while ( pSrc < pEnd ) { - uint8_t r = pSrc[2]; - uint8_t g = pSrc[1]; - uint8_t b = pSrc[0]; - uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255 + const uint8_t r = pSrc[2]; + const uint8_t g = pSrc[1]; + const uint8_t b = pSrc[0]; + const uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255 *pDst++ = r; *pDst++ = g; *pDst++ = b; *pDst++ = a; - pSrc += 4; + pSrc += 4; } } + + static void ABGRswizzleBGRA( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly + { + const uint8_t* pEnd = pSrc + nSize; + while ( pSrc < pEnd ) + { + const uint8_t r = pSrc[3]; + const uint8_t g = pSrc[2]; + const uint8_t b = pSrc[1]; + const uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255 + + *pDst++ = b; + *pDst++ = g; + *pDst++ = r; + *pDst++ = a; + pSrc += 4; + } + } +#if 0 + static void ABGRswizzleRGBA( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly + { + const uint8_t* pEnd = pSrc + nSize; + while ( pSrc < pEnd ) + { + const uint8_t r = pSrc[3]; + const uint8_t g = pSrc[2]; + const uint8_t b = pSrc[1]; + const uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255 + + *pDst++ = r; + *pDst++ = g; + *pDst++ = b; + *pDst++ = a; + pSrc += 4; + } + } +#endif }; class Transpose4096x4 { + /* + . Source layout = 4096x4 @ 32-bit + . +----+----+----+----+----+ + . |BGRA|BGRA|BGRA|... |BGRA| phase 0 + . +----+----+----+----+----+ + . |BGRA|BGRA|BGRA|... |BGRA| phase 1 + . +----+----+----+----+----| + . |BGRA|BGRA|BGRA|... |BGRA| phase 2 + . +----+----+----+----+----+ + . |BGRA|BGRA|BGRA|... |BGRA| phase 3 + . +----+----+----+----+----+ + . 0 1 2 4095 column + . + . Destination layout = 16x1024 @ 32-bit + . | phase 0 | phase 1 | phase 2 | phase 3 | + . +----+----+----+----+----+----+----+----+ + . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0 + . +----+----+----+----+----+----+----+----+ + . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1 + . +----+----+----+----+----+----+----+----+ + . |... |... |... |... |... |... |... |... | + . +----+----+----+----+----+----+----+----+ + . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1024 + . +----+----+----+----+----+----+----+----+ + . \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels + . 64 byte 64 byte 64 byte 64 byte + */ + public: static void transposeTo64x256( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) { - /* - Source layout = 4096x4 @ 32-bit - +----+----+----+----+----+ - |BGRA|BGRA|BGRA|... |BGRA| phase 0 - +----+----+----+----+----+ - |BGRA|BGRA|BGRA|... |BGRA| phase 1 - +----+----+----+----+----| - |BGRA|BGRA|BGRA|... |BGRA| phase 2 - +----+----+----+----+----+ - |BGRA|BGRA|BGRA|... |BGRA| phase 3 - +----+----+----+----+----+ - 0 1 2 4095 column - - Destination layout = 16x1024 @ 32-bit - | phase 0 | phase 1 | phase 2 | phase 3 | - +----+----+----+----+----+----+----+----+ - |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0 - +----+----+----+----+----+----+----+----+ - |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1 - +----+----+----+----+----+----+----+----+ - |... |... |... |... |... |... |... |... | - +----+----+----+----+----+----+----+----+ - |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1024 - +----+----+----+----+----+----+----+----+ - \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels - 64 byte - */ - /* */ uint8_t *pTmp = pDst; const uint32_t nBPP = 4; // bytes per pixel for( int iPhase = 0; iPhase < 4; iPhase++ ) { - pDst = pTmp + (iPhase * 16 * nBPP); + pDst = pTmp + (iPhase * 16 * nBPP); // dst is 16-px column for( int x = 0; x < 4096/16; x++ ) // 4096px/16 px = 256 columns { @@ -5017,16 +5056,34 @@ Update_t CmdNTSC (int nArgs) static void transposeFrom64x256( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) { + const uint8_t *pTmp = pSrc; + const uint32_t nBPP = 4; // bytes per pixel + for( int iPhase = 0; iPhase < 4; iPhase++ ) { + pSrc = pTmp + (iPhase * 16 * nBPP); // src is 16-px column for( int y = 0; y < 256; y++ ) { + for( int i = 0; i < 16*nBPP; i++ ) // 16 px, 32-bit + *pDst++ = *pSrc++; + + pSrc -= (16*nBPP); + pSrc += (64*nBPP); // move to next scan line } } } }; - uint32_t* pChromaTable = NTSC_VideoGetChromaTable( false, false ); + bool bColorTV = (g_eVideoType == VT_COLOR_TVEMU); + + uint32_t* pChromaTable = NTSC_VideoGetChromaTable( false, bColorTV ); + char aStatusText[64] = "Loaded"; + +//uint8_t* pTmp = (uint8_t*) pChromaTable; +//*pTmp++ = 0xFF; // b +//*pTmp++ = 0x00; // g +//*pTmp++ = 0x00; // r +//*pTmp++ = 0xFF; // a if (nFound) { @@ -5049,7 +5106,6 @@ Update_t CmdNTSC (int nArgs) // need to save 32-bit bpp as 24-bit bpp // VideoSaveScreenShot() Transpose4096x4::transposeTo64x256( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); - Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, pSwizzled ); // Note: Swizzle in-place! // Write BMP header WinBmpHeader_t bmp, *pBmp = &bmp; @@ -5059,7 +5115,7 @@ Update_t CmdNTSC (int nArgs) else { // RAW has no header - Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); + Swizzle32::RGBAswapBGRA( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled ); } nWrote = fwrite( pSwizzled, g_nChromaSize, 1, pFile ); @@ -5075,34 +5131,27 @@ Update_t CmdNTSC (int nArgs) } else { - ConsoleFilename::update( "File: " ); + ConsoleFilename::update( "File" ); ConsoleBufferPush( TEXT( "Error couldn't open file for writing." ) ); } } else if (iParam == PARAM_LOAD) { - char aStatusText[64] = "Loaded"; - FILE *pFile = fopen( sPaletteFilePath, "rb" ); if( pFile ) { strcpy( aStatusText, "Loaded" ); // Get File Size - size_t nFileSize = _GetFileSize( pFile ); + size_t nFileSize = _GetFileSize( pFile ); uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ]; - - if( nFileSize != g_nChromaSize ) - { - fclose( pFile ); - return ConsoleUpdate(); - } + bool bSwizzle = true; if( iFileType == TYPE_BMP ) { - WinBmpHeader_t bmp, *pBmp = &bmp; - fread( pBmp, sizeof( WinBmpHeader_t ), 1, pFile ); + WinBmpHeader4_t bmp, *pBmp = &bmp; + fread( pBmp, sizeof( WinBmpHeader4_t ), 1, pFile ); fseek( pFile, pBmp->nOffsetData, SEEK_SET ); if( 0 @@ -5115,19 +5164,42 @@ Update_t CmdNTSC (int nArgs) strcpy( aStatusText, "Bitmap not 64x256@32" ); goto _error; } + + if(pBmp->nStructSize == 0x28) + { + if( pBmp->nCompression == 0) // BI_RGB mode + bSwizzle = false; + } + else // 0x7C version4 bitmap + { + if( pBmp->nCompression == 3 ) // BI_BITFIELDS + { + if((pBmp->nRedMask == 0xFF000000 ) // Gimp writes in ABGR order + && (pBmp->nGreenMask == 0x00FF0000 ) + && (pBmp->nBlueMask == 0x0000FF00 )) + bSwizzle = true; + } + } } + else + if( nFileSize != g_nChromaSize ) + { + sprintf( aStatusText, "Raw size != %d", 64*256*4 ); + goto _error; + } + size_t nRead = fread( pSwizzled, g_nChromaSize, 1, pFile ); if( iFileType == TYPE_BMP ) { Transpose4096x4::transposeFrom64x256( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); - Swizzle32::swizzleRB( g_nChromaSize, (uint8_t*)pChromaTable, (uint8_t*)pChromaTable ); // Note: Swizzle in-place! - } - else // RAW - { - Swizzle32::swizzleRB( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); + if( bSwizzle ) + Swizzle32::ABGRswizzleBGRA( g_nChromaSize, (uint8_t*) pChromaTable, (uint8_t*) pChromaTable ); } + else + Swizzle32::RGBAswapBGRA( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable ); + _error: fclose( pFile ); delete [] pSwizzled; From f794f3f4c6428b52375ecc45a82e381343e1a1be Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 22:50:07 -0800 Subject: [PATCH 090/121] Debugger 2.9.0.1: implemented cd command --- docs/Debugger_Changelog.txt | 1 + source/Debugger/Debug.cpp | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/Debugger_Changelog.txt b/docs/Debugger_Changelog.txt index 57a0e777..004995ba 100644 --- a/docs/Debugger_Changelog.txt +++ b/docs/Debugger_Changelog.txt @@ -1,5 +1,6 @@ /* +.1 Fixed: Implemented missing debugger "CD" command 2.9.0.0 Added: ntsc save [filename], ntsc load [filename], to save/load the NTSC palette. Default filename is "AppleWinNTSC4096x4@32.data" To load this file in GIMP: Open, Select File Type: "Raw image data", Raw image data (*.data), RGB Alpha, Width: 4096, Height: 4 diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 6184bb1f..8db33498 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -48,7 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ALLOW_INPUT_LOWERCASE 1 // See /docs/Debugger_Changelog.txt for full details - const int DEBUGGER_VERSION = MAKE_VERSION(2,9,0,0); + const int DEBUGGER_VERSION = MAKE_VERSION(2,9,0,1); // Public _________________________________________________________________________________________ @@ -4041,6 +4041,26 @@ Update_t CmdConfigGetDebugDir (int nArgs) //=========================================================================== Update_t CmdConfigSetDebugDir (int nArgs) { + //if( nArgs > 2 ) + // return; + + // PWD directory +#if _WIN32 + // http://msdn.microsoft.com/en-us/library/aa365530(VS.85).aspx + TCHAR sPath[ MAX_PATH + 1 ]; + _tcscpy( sPath, g_sCurrentDir ); // TODO: debugger dir has no ` CONSOLE_COLOR_ESCAPE_CHAR ?!?! + _tcscat( sPath, g_aArgs[ 1 ].sArg ); + + if( SetCurrentImageDir( sPath ) ) + nArgs = 0; // intentional fall into +#else + #error "Need chdir() implemented" +#endif + + // PWD + if( nArgs == 0 ) + return CmdConfigGetDebugDir(0); + return ConsoleUpdate(); } From dfc4ef6d139c3f4ebca376f834bd50dfc119ceb9 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 10 Jan 2015 23:12:22 -0800 Subject: [PATCH 091/121] Version 17 BMP Palette --- source/Video.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/Video.cpp b/source/Video.cpp index abf773b2..2c0a0039 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1064,7 +1064,9 @@ void VideoDisplayLogo () SelectObject(hFrameDC,font); // sprintf( szVersion, "NTSC Alpha v14 HorzClock" ); // sprintf( szVersion, "NTSC Alpha v15 Fraps" ); - sprintf( szVersion, "NTSC Alpha v16 Palette" ); +// sprintf( szVersion, "NTSC Alpha v16 Palette" ); + sprintf( szVersion, "NTSC Alpha v17 BMP Palette" ); + xoff = -g_nViewportCX + g_nViewportCX/6; yoff = +g_nViewportCY/16; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); From f5869776ddb040d64805c62e2431c493812d76c9 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sun, 11 Jan 2015 08:46:51 -0800 Subject: [PATCH 092/121] DOC: Fix swizzle resolution (64x256) comment --- source/Debugger/Debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 8db33498..1441ad97 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -5038,7 +5038,7 @@ Update_t CmdNTSC (int nArgs) . +----+----+----+----+----+ . 0 1 2 4095 column . - . Destination layout = 16x1024 @ 32-bit + . Destination layout = 64x256 @ 32-bit . | phase 0 | phase 1 | phase 2 | phase 3 | . +----+----+----+----+----+----+----+----+ . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0 @@ -5047,7 +5047,7 @@ Update_t CmdNTSC (int nArgs) . +----+----+----+----+----+----+----+----+ . |... |... |... |... |... |... |... |... | . +----+----+----+----+----+----+----+----+ - . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1024 + . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 255 . +----+----+----+----+----+----+----+----+ . \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels . 64 byte 64 byte 64 byte 64 byte From e6deaee6ae5838e73cbbcbe83c75461643322cae Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Tue, 13 Jan 2015 11:02:42 -0800 Subject: [PATCH 093/121] Remove alt CHROMA_BLUR, added NTSC_REMOVE_WHITE_RINGING, NTSC_REMOVE_BLACK_GHOSTING --- source/NTSC.cpp | 90 ++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index e11d4f0b..ed9f18f4 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -30,7 +30,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NTSC.h" #include "NTSC_CharSet.cpp" -#define NTSC_REMOVE_WHITE_RING 1 // 0 = theoritical dimmed white, 1 = practical pure white +#define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white, 1 = practical pure white +#define NTSC_REMOVE_BLACK_GHOSTING 1 + #define DEBUG_PHASE_ZERO 0 #define ALT_TABLE 0 @@ -59,25 +61,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // sadly float64 precision is needed #define real double - #ifndef CHROMA_BLUR - #define CHROMA_BLUR 1 // Default: 1; 1 = blur along ~8 pixels; 0 = sharper - #endif - - #ifndef CHROMA_FILTER - #define CHROMA_FILTER 1 // If no chroma blur; 0 = use chroma as-is, 1 = soft chroma blur, strong color fringes 2 = more blur, muted chroma fringe - #endif - - #if CHROMA_BLUR - //#define CYCLESTART (PI/4.f) // PI/4 = 45 degrees - #define CYCLESTART (DEG_TO_RAD(45)) - #else // sharpness is higher, less color bleed - #if CHROMA_FILTER == 2 - #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = initFilterSignal(z); - #else - // #define CYCLESTART DEG_TO_RAD(90) // (PI*0.5) // PI/2 = 90 degrees // HGR: Great, GR: fail on brown - #define CYCLESTART DEG_TO_RAD(115.f) // GR perfect match of slow method - #endif - #endif + //#define CYCLESTART (PI/4.f) // PI/4 = 45 degrees + #define CYCLESTART (DEG_TO_RAD(45)) // Types @@ -817,39 +802,20 @@ static void initChromaPhaseTables (void) for(int k = 0; k < 2; k++ ) { -#if CHROMA_BLUR //z = z * 1.25; zz = initFilterSignal(z); c = initFilterChroma(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees y0 = initFilterLuma0 (zz); y1 = initFilterLuma1 (zz - c); -#else // CHROMA_BLUR + y0 = y0 + (z - y0) / 4.0; y1 = y0; // fix TV mode - #if CHROMA_FILTER == 0 - c = z; // sharper; "Mostly" correct _if_ CYCLESTART = 115 degrees - #endif // CHROMA_FILTER - #if CHROMA_FILTER == 1 // soft chroma blur, strong color fringes - // NOTE: This has incorrect colors! Chroma is (115-45)=70 degrees out of phase! violet <-> orange, green <-> blue - c = (z - y0); // Original -- smoother, white is solid, brighter; other colors - // -> - // c = (z - (y0 + (z-y0)/4)) - // c = z - y0 - (z-y0)/4 - // c = z - y0 - z/4 + y0/4 - // c = z-z/4 - y0+y0/4; // Which is clearly wrong, unless CYCLESTART DEG_TO_RAD(115) - // This mode looks the most accurate for white, has better color fringes - #endif - #if CHROMA_FILTER == 2 // more blur, muted chroma fringe - // White has too much ringing, and the color fringes are muted - c = initFilterSignal(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees - #endif -#endif // CHROMA_BLUR c = c * 2.f; i = i + (c * cos(phi) - i) / 8.f; q = q + (c * sin(phi) - q) / 8.f; - phi += RAD_45; //(PI / 4); + phi += RAD_45; // if (fabs((RAD_360) - phi) < 0.001) // phi = phi - RAD_360; // 2 * PI; } // k @@ -889,15 +855,29 @@ static void initChromaPhaseTables (void) r64 = y0 + (I_TO_R * i) + (Q_TO_R * q); g64 = y0 + (I_TO_G * i) + (Q_TO_G * q); b64 = y0 + (I_TO_B * i) + (Q_TO_B * q); -#if NTSC_REMOVE_WHITE_RING - // Remove white ringing - if(brightness > 0.9f) - b64 = g64 = r64 = 1.0; -#endif + b32 = clampZeroOne( (float)b64); g32 = clampZeroOne( (float)g64); r32 = clampZeroOne( (float)r64); +#if NTSC_REMOVE_WHITE_RINGING + if( (s & 15) == 15 ) + { + r32 = 1; + g32 = 1; + b32 = 1; + } +#endif + +#if NTSC_REMOVE_BLACK_GHOSTING + if( (s & 15) == 0 ) + { + r32 = 0; + g32 = 0; + b32 = 0; + } +#endif + g_aHueMonitor[phase][s].b = (uint8_t)(b32 * 255); g_aHueMonitor[phase][s].g = (uint8_t)(g32 * 255); g_aHueMonitor[phase][s].r = (uint8_t)(r32 * 255); @@ -911,6 +891,24 @@ static void initChromaPhaseTables (void) g32 = clampZeroOne( (float)g64 ); r32 = clampZeroOne( (float)r64 ); +#if NTSC_REMOVE_WHITE_RINGING + if( (s & 15) == 15 ) + { + r32 = 1; + g32 = 1; + b32 = 1; + } +#endif + +#if NTSC_REMOVE_BLACK_GHOSTING + if( (s & 15) == 0 ) + { + r32 = 0; + g32 = 0; + b32 = 0; + } +#endif + g_aHueColorTV[phase][s].b = (uint8_t)(b32 * 255); g_aHueColorTV[phase][s].g = (uint8_t)(g32 * 255); g_aHueColorTV[phase][s].r = (uint8_t)(r32 * 255); From e1c56ba38693127790ab5cd3320668f04334e1f1 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Tue, 13 Jan 2015 11:47:04 -0800 Subject: [PATCH 094/121] Fixed HGR display for Archon's end of line green white fringe --- source/NTSC.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index ed9f18f4..1a2f33c3 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -30,8 +30,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NTSC.h" #include "NTSC_CharSet.cpp" -#define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white, 1 = practical pure white -#define NTSC_REMOVE_BLACK_GHOSTING 1 +#define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white has chroma, 1 = pure white without chroma tinting +#define NTSC_REMOVE_BLACK_GHOSTING 1 // 1 = remove black smear/smudges carrying over #define DEBUG_PHASE_ZERO 0 @@ -707,21 +707,19 @@ inline void updateVideoScannerHorzEOL() //VIDEO_DRAW_ENDLINE(); if (g_nColorBurstPixels < 2) { - g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); -#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer + // NOTE: This writes out-of-bounds for a 560x384 framebuffer + g_pFuncUpdateBnWPixel(0); g_pFuncUpdateBnWPixel(0); g_pFuncUpdateBnWPixel(0); g_pFuncUpdateBnWPixel(0); -#endif } else { - g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); -#if 0 // BUGFIX: This writes out-of-bounds for a 560x384 framebuffer + // NOTE: This writes out-of-bounds for a 560x384 framebuffer g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(0); -#endif + g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); // BUGFIX: ARCHON: green fringe on end of line } } From 79c9bb9ee46a151545fab312522119dd3378f7dd Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 17 Jan 2015 15:06:32 +0000 Subject: [PATCH 095/121] Update VS2013 project files --- AppleWinExpress2013.vcxproj | 2 ++ AppleWinExpress2013.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj index 87520852..95b86697 100644 --- a/AppleWinExpress2013.vcxproj +++ b/AppleWinExpress2013.vcxproj @@ -74,6 +74,7 @@ + @@ -149,6 +150,7 @@ + diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters index 2551d0ed..6b8315a3 100644 --- a/AppleWinExpress2013.vcxproj.filters +++ b/AppleWinExpress2013.vcxproj.filters @@ -169,6 +169,9 @@ Source Files\Debugger + + Source Files\Video + @@ -417,6 +420,9 @@ Source Files\Disk + + Source Files\Video + From f3cb2e35bf66bac87075af21611c1e87c51e6c10 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 17 Jan 2015 11:15:00 -0800 Subject: [PATCH 096/121] Fixed DHGR blurry text introduced in commit e6deaee6ae5838e73cbbcbe83c75461643322cae --- source/NTSC.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1a2f33c3..5894c4e2 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -806,16 +806,11 @@ static void initChromaPhaseTables (void) y0 = initFilterLuma0 (zz); y1 = initFilterLuma1 (zz - c); - y0 = y0 + (z - y0) / 4.0; - y1 = y0; // fix TV mode - c = c * 2.f; i = i + (c * cos(phi) - i) / 8.f; q = q + (c * sin(phi) - q) / 8.f; phi += RAD_45; -// if (fabs((RAD_360) - phi) < 0.001) -// phi = phi - RAD_360; // 2 * PI; } // k } // samples From 4886b5daeaa1b42ec9a2ffd665d4d793310e84a5 Mon Sep 17 00:00:00 2001 From: michaelangel007 Date: Sat, 17 Jan 2015 11:19:29 -0800 Subject: [PATCH 097/121] version 18 Blurry 80-col text --- source/Video.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/Video.cpp b/source/Video.cpp index 2c0a0039..0c5909a7 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1065,8 +1065,16 @@ void VideoDisplayLogo () // sprintf( szVersion, "NTSC Alpha v14 HorzClock" ); // sprintf( szVersion, "NTSC Alpha v15 Fraps" ); // sprintf( szVersion, "NTSC Alpha v16 Palette" ); - sprintf( szVersion, "NTSC Alpha v17 BMP Palette" ); +// sprintf( szVersion, "NTSC Alpha v17 BMP Palette" ); + sprintf( szVersion, "NTSC Alpha v18" ); + xoff = -g_nViewportCX + g_nViewportCX/6; + yoff = -g_nViewportCY/16; + DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); + DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); + DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); + + sprintf( szVersion, "Blurry 80-col Text" ); xoff = -g_nViewportCX + g_nViewportCX/6; yoff = +g_nViewportCY/16; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); From e03b90fbe8421b4375ad50b79accadc5789cb6d2 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 21 Mar 2016 22:27:09 +0000 Subject: [PATCH 098/121] Support VS2008 --- ApplewinExpress9.00.vcproj | 12 ++++++++++++ source/StdAfx.h | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ApplewinExpress9.00.vcproj b/ApplewinExpress9.00.vcproj index 55966eea..27e7e9f1 100644 --- a/ApplewinExpress9.00.vcproj +++ b/ApplewinExpress9.00.vcproj @@ -846,6 +846,18 @@ RelativePath=".\source\Frame.h" > + + + + + + diff --git a/source/StdAfx.h b/source/StdAfx.h index 010d50f8..989c60da 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -25,7 +25,13 @@ #include #include #include -#include // uint8_t +#if _MSC_VER >= 1600 // supported from VS2010 (cl.exe v16.00) +#include // cleanup WORD DWORD -> uint16_t uint32_t +#else +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +#endif #include #include // WM_MOUSEWHEEL From 95273ed45c77c5c6f655ad6e3173251cecb6c124 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 21 Mar 2016 22:37:25 +0000 Subject: [PATCH 099/121] Add only libyaml first (so this big 105 commit does not pollute the main merge from master) --- libyaml/LICENSE | 19 + libyaml/README | 27 + libyaml/doc/doxygen.cfg | 222 + libyaml/doc/html/annotated.html | 83 + libyaml/doc/html/bc_s.png | Bin 0 -> 677 bytes libyaml/doc/html/classes.html | 78 + libyaml/doc/html/closed.png | Bin 0 -> 126 bytes libyaml/doc/html/doxygen.css | 949 +++++ libyaml/doc/html/doxygen.png | Bin 0 -> 3942 bytes libyaml/doc/html/files.html | 72 + libyaml/doc/html/functions.html | 123 + libyaml/doc/html/functions_0x62.html | 116 + libyaml/doc/html/functions_0x63.html | 119 + libyaml/doc/html/functions_0x64.html | 115 + libyaml/doc/html/functions_0x65.html | 142 + libyaml/doc/html/functions_0x66.html | 111 + libyaml/doc/html/functions_0x68.html | 112 + libyaml/doc/html/functions_0x69.html | 124 + libyaml/doc/html/functions_0x6b.html | 103 + libyaml/doc/html/functions_0x6c.html | 120 + libyaml/doc/html/functions_0x6d.html | 128 + libyaml/doc/html/functions_0x6e.html | 103 + libyaml/doc/html/functions_0x6f.html | 112 + libyaml/doc/html/functions_0x70.html | 132 + libyaml/doc/html/functions_0x71.html | 103 + libyaml/doc/html/functions_0x72.html | 119 + libyaml/doc/html/functions_0x73.html | 195 + libyaml/doc/html/functions_0x74.html | 147 + libyaml/doc/html/functions_0x75.html | 103 + libyaml/doc/html/functions_0x76.html | 112 + libyaml/doc/html/functions_0x77.html | 109 + libyaml/doc/html/functions_vars.html | 123 + libyaml/doc/html/functions_vars_0x62.html | 116 + libyaml/doc/html/functions_vars_0x63.html | 119 + libyaml/doc/html/functions_vars_0x64.html | 115 + libyaml/doc/html/functions_vars_0x65.html | 142 + libyaml/doc/html/functions_vars_0x66.html | 111 + libyaml/doc/html/functions_vars_0x68.html | 112 + libyaml/doc/html/functions_vars_0x69.html | 124 + libyaml/doc/html/functions_vars_0x6b.html | 103 + libyaml/doc/html/functions_vars_0x6c.html | 120 + libyaml/doc/html/functions_vars_0x6d.html | 128 + libyaml/doc/html/functions_vars_0x6e.html | 103 + libyaml/doc/html/functions_vars_0x6f.html | 112 + libyaml/doc/html/functions_vars_0x70.html | 132 + libyaml/doc/html/functions_vars_0x71.html | 103 + libyaml/doc/html/functions_vars_0x72.html | 119 + libyaml/doc/html/functions_vars_0x73.html | 195 + libyaml/doc/html/functions_vars_0x74.html | 147 + libyaml/doc/html/functions_vars_0x75.html | 103 + libyaml/doc/html/functions_vars_0x76.html | 112 + libyaml/doc/html/functions_vars_0x77.html | 109 + libyaml/doc/html/globals.html | 699 ++++ libyaml/doc/html/globals_defs.html | 113 + libyaml/doc/html/globals_enum.html | 110 + libyaml/doc/html/globals_eval.html | 405 ++ libyaml/doc/html/globals_func.html | 228 ++ libyaml/doc/html/globals_type.html | 158 + libyaml/doc/html/group__basic.html | 349 ++ libyaml/doc/html/group__emitter.html | 845 ++++ libyaml/doc/html/group__events.html | 691 ++++ libyaml/doc/html/group__export.html | 91 + libyaml/doc/html/group__nodes.html | 824 ++++ libyaml/doc/html/group__parser.html | 635 +++ libyaml/doc/html/group__styles.html | 251 ++ libyaml/doc/html/group__tokens.html | 276 ++ libyaml/doc/html/group__version.html | 137 + libyaml/doc/html/index.html | 63 + libyaml/doc/html/modules.html | 74 + libyaml/doc/html/nav_f.png | Bin 0 -> 159 bytes libyaml/doc/html/nav_h.png | Bin 0 -> 97 bytes libyaml/doc/html/open.png | Bin 0 -> 118 bytes .../doc/html/structyaml__alias__data__s.html | 137 + libyaml/doc/html/structyaml__document__s.html | 264 ++ libyaml/doc/html/structyaml__emitter__s.html | 1321 ++++++ libyaml/doc/html/structyaml__event__s.html | 525 +++ libyaml/doc/html/structyaml__mark__s.html | 137 + .../doc/html/structyaml__node__pair__s.html | 120 + libyaml/doc/html/structyaml__node__s.html | 449 +++ libyaml/doc/html/structyaml__parser__s.html | 1248 ++++++ .../doc/html/structyaml__simple__key__s.html | 126 + .../html/structyaml__tag__directive__s.html | 120 + libyaml/doc/html/structyaml__token__s.html | 442 ++ .../structyaml__version__directive__s.html | 120 + libyaml/doc/html/tab_a.png | Bin 0 -> 140 bytes libyaml/doc/html/tab_b.png | Bin 0 -> 178 bytes libyaml/doc/html/tab_h.png | Bin 0 -> 192 bytes libyaml/doc/html/tab_s.png | Bin 0 -> 189 bytes libyaml/doc/html/tabs.css | 59 + libyaml/doc/html/yaml_8h.html | 546 +++ libyaml/include/yaml.h | 1971 +++++++++ libyaml/src/api.c | 1392 +++++++ libyaml/src/dumper.c | 394 ++ libyaml/src/emitter.c | 2329 +++++++++++ libyaml/src/loader.c | 444 ++ libyaml/src/parser.c | 1374 +++++++ libyaml/src/reader.c | 469 +++ libyaml/src/scanner.c | 3580 +++++++++++++++++ libyaml/src/writer.c | 141 + libyaml/src/yaml_private.h | 657 +++ libyaml/win32/config.h | 4 + libyaml/win32/yaml2008.vcproj | 215 + libyaml/win32/yaml2013.vcxproj | 100 + libyaml/win32/yaml2013.vcxproj.filters | 54 + 104 files changed, 31233 insertions(+) create mode 100644 libyaml/LICENSE create mode 100644 libyaml/README create mode 100644 libyaml/doc/doxygen.cfg create mode 100644 libyaml/doc/html/annotated.html create mode 100644 libyaml/doc/html/bc_s.png create mode 100644 libyaml/doc/html/classes.html create mode 100644 libyaml/doc/html/closed.png create mode 100644 libyaml/doc/html/doxygen.css create mode 100644 libyaml/doc/html/doxygen.png create mode 100644 libyaml/doc/html/files.html create mode 100644 libyaml/doc/html/functions.html create mode 100644 libyaml/doc/html/functions_0x62.html create mode 100644 libyaml/doc/html/functions_0x63.html create mode 100644 libyaml/doc/html/functions_0x64.html create mode 100644 libyaml/doc/html/functions_0x65.html create mode 100644 libyaml/doc/html/functions_0x66.html create mode 100644 libyaml/doc/html/functions_0x68.html create mode 100644 libyaml/doc/html/functions_0x69.html create mode 100644 libyaml/doc/html/functions_0x6b.html create mode 100644 libyaml/doc/html/functions_0x6c.html create mode 100644 libyaml/doc/html/functions_0x6d.html create mode 100644 libyaml/doc/html/functions_0x6e.html create mode 100644 libyaml/doc/html/functions_0x6f.html create mode 100644 libyaml/doc/html/functions_0x70.html create mode 100644 libyaml/doc/html/functions_0x71.html create mode 100644 libyaml/doc/html/functions_0x72.html create mode 100644 libyaml/doc/html/functions_0x73.html create mode 100644 libyaml/doc/html/functions_0x74.html create mode 100644 libyaml/doc/html/functions_0x75.html create mode 100644 libyaml/doc/html/functions_0x76.html create mode 100644 libyaml/doc/html/functions_0x77.html create mode 100644 libyaml/doc/html/functions_vars.html create mode 100644 libyaml/doc/html/functions_vars_0x62.html create mode 100644 libyaml/doc/html/functions_vars_0x63.html create mode 100644 libyaml/doc/html/functions_vars_0x64.html create mode 100644 libyaml/doc/html/functions_vars_0x65.html create mode 100644 libyaml/doc/html/functions_vars_0x66.html create mode 100644 libyaml/doc/html/functions_vars_0x68.html create mode 100644 libyaml/doc/html/functions_vars_0x69.html create mode 100644 libyaml/doc/html/functions_vars_0x6b.html create mode 100644 libyaml/doc/html/functions_vars_0x6c.html create mode 100644 libyaml/doc/html/functions_vars_0x6d.html create mode 100644 libyaml/doc/html/functions_vars_0x6e.html create mode 100644 libyaml/doc/html/functions_vars_0x6f.html create mode 100644 libyaml/doc/html/functions_vars_0x70.html create mode 100644 libyaml/doc/html/functions_vars_0x71.html create mode 100644 libyaml/doc/html/functions_vars_0x72.html create mode 100644 libyaml/doc/html/functions_vars_0x73.html create mode 100644 libyaml/doc/html/functions_vars_0x74.html create mode 100644 libyaml/doc/html/functions_vars_0x75.html create mode 100644 libyaml/doc/html/functions_vars_0x76.html create mode 100644 libyaml/doc/html/functions_vars_0x77.html create mode 100644 libyaml/doc/html/globals.html create mode 100644 libyaml/doc/html/globals_defs.html create mode 100644 libyaml/doc/html/globals_enum.html create mode 100644 libyaml/doc/html/globals_eval.html create mode 100644 libyaml/doc/html/globals_func.html create mode 100644 libyaml/doc/html/globals_type.html create mode 100644 libyaml/doc/html/group__basic.html create mode 100644 libyaml/doc/html/group__emitter.html create mode 100644 libyaml/doc/html/group__events.html create mode 100644 libyaml/doc/html/group__export.html create mode 100644 libyaml/doc/html/group__nodes.html create mode 100644 libyaml/doc/html/group__parser.html create mode 100644 libyaml/doc/html/group__styles.html create mode 100644 libyaml/doc/html/group__tokens.html create mode 100644 libyaml/doc/html/group__version.html create mode 100644 libyaml/doc/html/index.html create mode 100644 libyaml/doc/html/modules.html create mode 100644 libyaml/doc/html/nav_f.png create mode 100644 libyaml/doc/html/nav_h.png create mode 100644 libyaml/doc/html/open.png create mode 100644 libyaml/doc/html/structyaml__alias__data__s.html create mode 100644 libyaml/doc/html/structyaml__document__s.html create mode 100644 libyaml/doc/html/structyaml__emitter__s.html create mode 100644 libyaml/doc/html/structyaml__event__s.html create mode 100644 libyaml/doc/html/structyaml__mark__s.html create mode 100644 libyaml/doc/html/structyaml__node__pair__s.html create mode 100644 libyaml/doc/html/structyaml__node__s.html create mode 100644 libyaml/doc/html/structyaml__parser__s.html create mode 100644 libyaml/doc/html/structyaml__simple__key__s.html create mode 100644 libyaml/doc/html/structyaml__tag__directive__s.html create mode 100644 libyaml/doc/html/structyaml__token__s.html create mode 100644 libyaml/doc/html/structyaml__version__directive__s.html create mode 100644 libyaml/doc/html/tab_a.png create mode 100644 libyaml/doc/html/tab_b.png create mode 100644 libyaml/doc/html/tab_h.png create mode 100644 libyaml/doc/html/tab_s.png create mode 100644 libyaml/doc/html/tabs.css create mode 100644 libyaml/doc/html/yaml_8h.html create mode 100644 libyaml/include/yaml.h create mode 100644 libyaml/src/api.c create mode 100644 libyaml/src/dumper.c create mode 100644 libyaml/src/emitter.c create mode 100644 libyaml/src/loader.c create mode 100644 libyaml/src/parser.c create mode 100644 libyaml/src/reader.c create mode 100644 libyaml/src/scanner.c create mode 100644 libyaml/src/writer.c create mode 100644 libyaml/src/yaml_private.h create mode 100644 libyaml/win32/config.h create mode 100644 libyaml/win32/yaml2008.vcproj create mode 100644 libyaml/win32/yaml2013.vcxproj create mode 100644 libyaml/win32/yaml2013.vcxproj.filters diff --git a/libyaml/LICENSE b/libyaml/LICENSE new file mode 100644 index 00000000..050ced23 --- /dev/null +++ b/libyaml/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006 Kirill Simonov + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libyaml/README b/libyaml/README new file mode 100644 index 00000000..d35ebcc9 --- /dev/null +++ b/libyaml/README @@ -0,0 +1,27 @@ +LibYAML - A C library for parsing and emitting YAML. + +To build and install the library, run: +$ ./configure +$ make +# make install + +If you checked the source code from the Subversion repository, run +$ ./bootstrap +$ ./configure +$ make +# make install + +For more information, check the LibYAML homepage: +'http://pyyaml.org/wiki/LibYAML'. + +Post your questions and opinions to the YAML-Core mailing list: +'http://lists.sourceforge.net/lists/listinfo/yaml-core'. + +Submit bug reports and feature requests to the LibYAML bug tracker: +'http://pyyaml.org/newticket?component=libyaml'. + +LibYAML is written by Kirill Simonov . It is released +under the MIT license. See the file LICENSE for more details. + +This project is developed for Python Software Foundation as a part of +Google Summer of Code under the mentorship of Clark Evans. diff --git a/libyaml/doc/doxygen.cfg b/libyaml/doc/doxygen.cfg new file mode 100644 index 00000000..a58bb177 --- /dev/null +++ b/libyaml/doc/doxygen.cfg @@ -0,0 +1,222 @@ +# Doxyfile 1.4.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = $(PACKAGE) +PROJECT_NUMBER = $(VERSION) +OUTPUT_DIRECTORY = $(top_builddir)/doc/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = $(top_srcdir)/include/ +FILE_PATTERNS = *.h +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 1 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = "YAML_DECLARE(type)=type" +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/libyaml/doc/html/annotated.html b/libyaml/doc/html/annotated.html new file mode 100644 index 00000000..064df4b9 --- /dev/null +++ b/libyaml/doc/html/annotated.html @@ -0,0 +1,83 @@ + + + + + +yaml: Data Structures + + + + + + + + +

+
+
+
Data Structures
+
+
+
Here are the data structures with brief descriptions:
+ + + + + + + + + + + + +
yaml_alias_data_sThis structure holds aliases data
yaml_document_sThe document structure
yaml_emitter_sThe emitter structure
yaml_event_sThe event structure
yaml_mark_sThe pointer position
yaml_node_pair_sAn element of a mapping node
yaml_node_sThe node structure
yaml_parser_sThe parser structure
yaml_simple_key_sThis structure holds information about a potential simple key
yaml_tag_directive_sThe tag directive data
yaml_token_sThe token structure
yaml_version_directive_sThe version directive data
+
+ + + + + + diff --git a/libyaml/doc/html/bc_s.png b/libyaml/doc/html/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..e4018628b5b45cb4301037485a29d7d74ac22138 GIT binary patch literal 677 zcmV;W0$TlvP)X?0Pv5h+5!wElpi=&YL!gfY!djl#UDdPKy97F|A-deTa@qo3BWh1YQIvzmHR^g zFjV4I6pLB7_*vEZk^%p7c7Bh>0`4r^X#gpJE_Vz9fSHKqclcZaV^k3gX%h+1`u||O zZ+BY?7(R=ayr^kXE=E0Dw=$Ud3VJ?9^Cz@hP?388Cw5>9TloOJ>^KczCgj zns2=|0!a|)Yq3{hjL{xyy7|Tk0N}Pe+g9PUTL!4{#;eUhrNd@!_T<>Vu+35c)h>sq ztgb?(6W3oFLz#%?OMEV@{j#4LuDvjVGZ~6hpQT8li5b0yjvK8c4efl+vSz5)P6 zle78)00_Iv5)&E~hnOdcd}L}i+MU>k+Q8#@KjqJJN`gRj(~)RmNrck9ht@LelPtVO zwp(J;k!T=gC#%o(13-^E+g@aqc()pf{+j|0w)AH*Mq$54UjLv#jV$RYpz3Vjg$$=u z>yjfBQOhL=^@+#4#$l|{~}HZ-?1Yy{lI*$N}*YDC`<{+;>_#gMXZdz4NI00000 LNkvXXu0mjfx86dR literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/classes.html b/libyaml/doc/html/classes.html new file mode 100644 index 00000000..d086d23d --- /dev/null +++ b/libyaml/doc/html/classes.html @@ -0,0 +1,78 @@ + + + + + +yaml: Data Structure Index + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+
+
Data Structure Index
+
+ + + + + + + diff --git a/libyaml/doc/html/closed.png b/libyaml/doc/html/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d4bd9fef2272c74b94762c9e2496177017775e GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VuAVNAAr*{o?>h22DDp4|bgj*t z)u^AqcA-V@guRYpb17F<&b?_~8HV>~XqWvB;^$!VVSTy0!eQcJp_yD7TIQA>7dijs YXf6~H5cs^Q6KEiVr>mdKI;Vst0NsWqGynhq literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/doxygen.css b/libyaml/doc/html/doxygen.css new file mode 100644 index 00000000..cee0d06b --- /dev/null +++ b/libyaml/doc/html/doxygen.css @@ -0,0 +1,949 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4CFE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 2px 5px; + background-color: #FBFCFD; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/libyaml/doc/html/doxygen.png b/libyaml/doc/html/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..635ed52fce7057ac24df92ec7664088a881fa5d0 GIT binary patch literal 3942 zcmV-s51H_ZP)95ENDh(OT9xpYZC{M(=rqI* z+1erNEr&9zRjUI-4rN=4BBz>P@ys*xOjGRjzVE*Fx_qvyt9d@B@BO*&@8Mq!nM{Tc z_WoM84-~xLreSL9@vgZ{m2dF}`u=^ZF3syQ-s2tnBwCI3ZFvSfI20Wbj236~Urq*8Kfw@RKKfRQTgE>}uUHK^ptamY=o)LU(xy55zNQ(`qZ znZ&$O075mrrInIXQgw4%GCbMD8Vn`3n3$EaRwtP1D{A!Gs=e!L%3;ayv@I{rAw{xw z^x^>EIWQM8ob3m}$(BaupDMV;Ed8w5|i(*e`7rU$TOc&1o7`|!LyN5jHI z7uWAR!v4c2xMp?}QmRYyf>i}tYGU(g=>DW&==J@GbhR z5@BNVY3O$`^D%gk4khm9XpFhuwzxUhi9T=Du4rpVuYRSMPHeDqo+4htnZRU@G9`0& z9~p)CsFl1|t*wjfoTo&%davN^3RfJUhQ{ZZIAcD77X^XsF_iR&ZMQ;p>K5*+*48)x z+=<>nh+6Uq85jOkg>{z>a;+V`s(I;I%*5s+R@9a^wNoZ03(g9-EcH%uHvX&yp7`D#`9Kw>DU3s zjD-VuW_A-K)unlS4O3f>_B%pPONUmI#oyL};Lglp3=04>0eBBEw$D1k-$WTsoi#K* z$7h`NcyRZsZ#w~6I<%~u!^xDofYrzF>zVIj2N>Ijs`mVR(Oy&*9f}<{JtQj8jJT!oEc!NQXBq5y|6ET*N?7ox*E6#{i- z@_DLD^IYTtg|Pg?A~!7@OCd8p^)kxK%VBM84docx$Z{MvO)iiqep@or-N}TEU8$%; zJih?#yJ9)V1s_`}c3XbY9V}nEKwNz8ILmR|v)(w|D@oVG;=i`+$*)!(xH{9#$2Za;pyZ1wgU#)mHl|&8%iwu%yncO z`T32Ib0$D}j`c}}5M@M#7oR&G=QwU!!Ja*P7|NJt1@lo=d{_dY-q_lmDcH7{BHncF zR@^PmcLC6EsN?6N{fV3o8}>?h9X_@;=&-p7%tms7$_{3w(anwek_k&<&)~c$Ar?S> zy9gKavndTmxqAbE?SMgcWhXPENdKdz7ntt55Y3Hs3jjc~uR-#$tR(1a_abv9`-QzG z^J0Fsbd&yruq%xAsxf3rc=T}$Zx|AD%x{Fd=? z{qhl3kG5w-PqVK9-Gru%7UIEw)bt$ZMF|Z6HpmO)F%@GNT8yT|#FuWPxv@@Ic={;6 zU7)e!XG|1dx=kU|&|)+m+$&|Yw92Fa;*MnegXcCf8XsHfqg_F5t)3Jt8)EkXKuY21 zqt%4}@R8hK*(_JO0*H+Pa)6Pp&K49rKNeQEYb*x9WY`!`Vh3|80YF%I`lxv9_!$hD zOh$>zWaRIW!);6`vA$Zp;5lnGyX^^N%YEjCeJMHPolKCE1ttIqK<$0w&LcE8)`_c2 z^H^qf6ACV0t7FLLCsu#mL&Mb8gE@rZE#k+1Nrrxw+{N0^#bN*~!qt2>S4e#jC$a$` ze4@{)$aTEYq_!#2|t@Fj3e?w-XVuG$Z}kAR?_kgJAlZIJ)0{eHw#fybNooA zp02jyYVc&w!}m#BVP>ef2|U^J(A-#O1R#A&><*?Y! zOwml{CnE+aU3JfKE@uzge(qMY{^6siuXFt;+mMbapU;Ppejl=L#>s2#SMBbfP9AFT znEVA=TBtZ6d-GfF>kOxylg>Ek%qTp*h2ze!^^hOsmKOEE6b;maQ>~R>3#z`Zawbik z88OTykU3_!Atg^+vnM=1n}?%<$dHzn)?k&T#RWwb+*y;XNQbYNHKo3wr~&}Qa$id; z6^D*K9RTQZUuQVg)g~P%!BIiv+cXllt)KEP9IN)1udQKf>p|~lXj7K<-9}0Q%i9+K zXaF7qXclE>sf)7)J4_M%V{;(sFT7HN$o0#_qU#Ah1D{ zon=JihPcgG5xHuvQwOXBkt3(iUdx{6Gn|aa>@C9Cqg%rPK(+REZ4>6t3z7m@Aj;0l zSHh&%cKSJ*+WOJGwe?Y7d(9RAy)&NVS6uj}1m@U}jXH3oVQT9E0A)$ZDRdK>;_i;+ z7vbEoI7$1XK6vNxT(_sJ(GM4s92e;gB&Q zDO;(Ve^%gPG&lWW1fUf_=9-Q1%&`s%aD^o`Q2u`WI9V>Qm#D5?SW<)Njmt@aR5@6( zL4cdTo+Jg@>Brm1^_gf%0Z?}1AppR3NdFE5uzdpBZz;{Thd6SI-$gb2}pFAww$*j(2=s{mdz2E;lBvVcrN@}i2bC`Q5Y_;BID^f0J+ACVhyQsLg0@`okIk+i=LJ=3yvI*oASj62 za3C{Pu_fQ+atw!zN{$Shr*_UV=|jp4#CqWeGE?Jb`pq!|5bDES&-Ix=-N>DpydHqW z+-{QS+i)d;uGS)M%Suw9khR}3N82j|S{a#&Tctme0s%mTy<1S|;@M-+S4#o@!qr;r z+w(n=;@43Y_n#dI0Gb(T0{G7k-KY8k`MPM_Bss$?)SK){KJMrwv!vz42_U_Za zX7lDqiU8ZvCAfGpAtfVC5bQrYa4C)M9G$S4D&VqpJ8)lm$t5FAAR%ywf>*~VaivC70RVFXISv4Lx&tk^Cf1)qQ|rxp z*8H>)cgoM;(eKxH14u~~@JopNr9@A z#-yXVG?$es;EPqsn-j?45^L52U=nT#0A^T3JY$&B3EH&%2UHdv3P=_3$!n76!34ks zz^2ii@sXAu8LKYMmG=_^*qtiiOFNlG3?QYtG%wrCZh|)vlj8vq3sw~f1b8;_TMB>z zPSyDQy_9bbXD*#sNRGMzfSAwUD}ASX;ZGQcGdE=9q~ORU{v$}=z2Bc8EOe2S&);jS zCZB8P`hPoV1NBk)TQP2z{q$NL-GLUc7%>&fecE^E{I5gs?8!qTK7VgR7Z?}-`YG|z zVN-NvOlQ+B;~J*69_Xd1n-0MLKTY6&*%rTi*0^HXniz8{bCMsVpSXqs(GGO)*_#Kz z9YBCQ_VRhtwhMfppMh@OdxjCN0mH`5hKZr>UoxMx`W~u^kD&bskplglOiRxQvep*2 z0mk+kMP>J)K`8X3`6Zq|X~5IQ-_rrOn+_WvU{1Gs{ow1-Eb;K(Z?p$@ugXpr^?PM( z(5Hv;$*X=QZaqG_4q)N1v9sO(Dsei!;%IcIztt6YUs{yj z^77e`UYa^%<-Ts+d*b=ihKt?0_sj!ePNO@K*PGmGD*v^;rRAkduikx~UNk=@{XKeV zp_ir(dTaGVWBr{_02Kg2Xmlsn|IvIIRYivbo|L{yx}yX5Bte@P6C>1KyqvYnT{boB#j-07*qoM6N<$f^XQQ A+yDRo literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/files.html b/libyaml/doc/html/files.html new file mode 100644 index 00000000..1c48dd91 --- /dev/null +++ b/libyaml/doc/html/files.html @@ -0,0 +1,72 @@ + + + + + +yaml: File List + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ +
yaml.hPublic interface for libyaml
+
+ + + + + + diff --git a/libyaml/doc/html/functions.html b/libyaml/doc/html/functions.html new file mode 100644 index 00000000..df9299b2 --- /dev/null +++ b/libyaml/doc/html/functions.html @@ -0,0 +1,123 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- a -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x62.html b/libyaml/doc/html/functions_0x62.html new file mode 100644 index 00000000..a368fe95 --- /dev/null +++ b/libyaml/doc/html/functions_0x62.html @@ -0,0 +1,116 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- b -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x63.html b/libyaml/doc/html/functions_0x63.html new file mode 100644 index 00000000..be4df973 --- /dev/null +++ b/libyaml/doc/html/functions_0x63.html @@ -0,0 +1,119 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- c -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x64.html b/libyaml/doc/html/functions_0x64.html new file mode 100644 index 00000000..033adeb5 --- /dev/null +++ b/libyaml/doc/html/functions_0x64.html @@ -0,0 +1,115 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- d -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x65.html b/libyaml/doc/html/functions_0x65.html new file mode 100644 index 00000000..ece59bc5 --- /dev/null +++ b/libyaml/doc/html/functions_0x65.html @@ -0,0 +1,142 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- e -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x66.html b/libyaml/doc/html/functions_0x66.html new file mode 100644 index 00000000..10edc211 --- /dev/null +++ b/libyaml/doc/html/functions_0x66.html @@ -0,0 +1,111 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- f -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x68.html b/libyaml/doc/html/functions_0x68.html new file mode 100644 index 00000000..f0ec097a --- /dev/null +++ b/libyaml/doc/html/functions_0x68.html @@ -0,0 +1,112 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- h -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x69.html b/libyaml/doc/html/functions_0x69.html new file mode 100644 index 00000000..612ff197 --- /dev/null +++ b/libyaml/doc/html/functions_0x69.html @@ -0,0 +1,124 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- i -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x6b.html b/libyaml/doc/html/functions_0x6b.html new file mode 100644 index 00000000..53e0234f --- /dev/null +++ b/libyaml/doc/html/functions_0x6b.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- k -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x6c.html b/libyaml/doc/html/functions_0x6c.html new file mode 100644 index 00000000..7b3f6593 --- /dev/null +++ b/libyaml/doc/html/functions_0x6c.html @@ -0,0 +1,120 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- l -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x6d.html b/libyaml/doc/html/functions_0x6d.html new file mode 100644 index 00000000..56e3fa0a --- /dev/null +++ b/libyaml/doc/html/functions_0x6d.html @@ -0,0 +1,128 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- m -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x6e.html b/libyaml/doc/html/functions_0x6e.html new file mode 100644 index 00000000..c763a036 --- /dev/null +++ b/libyaml/doc/html/functions_0x6e.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- n -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x6f.html b/libyaml/doc/html/functions_0x6f.html new file mode 100644 index 00000000..c4116909 --- /dev/null +++ b/libyaml/doc/html/functions_0x6f.html @@ -0,0 +1,112 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- o -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x70.html b/libyaml/doc/html/functions_0x70.html new file mode 100644 index 00000000..03f9cbf8 --- /dev/null +++ b/libyaml/doc/html/functions_0x70.html @@ -0,0 +1,132 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- p -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x71.html b/libyaml/doc/html/functions_0x71.html new file mode 100644 index 00000000..01da5c9d --- /dev/null +++ b/libyaml/doc/html/functions_0x71.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- q -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x72.html b/libyaml/doc/html/functions_0x72.html new file mode 100644 index 00000000..d6394572 --- /dev/null +++ b/libyaml/doc/html/functions_0x72.html @@ -0,0 +1,119 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- r -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x73.html b/libyaml/doc/html/functions_0x73.html new file mode 100644 index 00000000..e295746b --- /dev/null +++ b/libyaml/doc/html/functions_0x73.html @@ -0,0 +1,195 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- s -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x74.html b/libyaml/doc/html/functions_0x74.html new file mode 100644 index 00000000..3197f756 --- /dev/null +++ b/libyaml/doc/html/functions_0x74.html @@ -0,0 +1,147 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- t -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x75.html b/libyaml/doc/html/functions_0x75.html new file mode 100644 index 00000000..609221bb --- /dev/null +++ b/libyaml/doc/html/functions_0x75.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- u -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x76.html b/libyaml/doc/html/functions_0x76.html new file mode 100644 index 00000000..fdae18df --- /dev/null +++ b/libyaml/doc/html/functions_0x76.html @@ -0,0 +1,112 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- v -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_0x77.html b/libyaml/doc/html/functions_0x77.html new file mode 100644 index 00000000..eff19afc --- /dev/null +++ b/libyaml/doc/html/functions_0x77.html @@ -0,0 +1,109 @@ + + + + + +yaml: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- w -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars.html b/libyaml/doc/html/functions_vars.html new file mode 100644 index 00000000..efd1a693 --- /dev/null +++ b/libyaml/doc/html/functions_vars.html @@ -0,0 +1,123 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- a -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x62.html b/libyaml/doc/html/functions_vars_0x62.html new file mode 100644 index 00000000..c7cb3b5a --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x62.html @@ -0,0 +1,116 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- b -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x63.html b/libyaml/doc/html/functions_vars_0x63.html new file mode 100644 index 00000000..5ea5cdd6 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x63.html @@ -0,0 +1,119 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- c -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x64.html b/libyaml/doc/html/functions_vars_0x64.html new file mode 100644 index 00000000..36493730 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x64.html @@ -0,0 +1,115 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- d -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x65.html b/libyaml/doc/html/functions_vars_0x65.html new file mode 100644 index 00000000..e9410d93 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x65.html @@ -0,0 +1,142 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+ + + + + + + diff --git a/libyaml/doc/html/functions_vars_0x66.html b/libyaml/doc/html/functions_vars_0x66.html new file mode 100644 index 00000000..cd32059c --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x66.html @@ -0,0 +1,111 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- f -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x68.html b/libyaml/doc/html/functions_vars_0x68.html new file mode 100644 index 00000000..eda098c1 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x68.html @@ -0,0 +1,112 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- h -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x69.html b/libyaml/doc/html/functions_vars_0x69.html new file mode 100644 index 00000000..69950737 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x69.html @@ -0,0 +1,124 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- i -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x6b.html b/libyaml/doc/html/functions_vars_0x6b.html new file mode 100644 index 00000000..498b2aec --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x6b.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- k -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x6c.html b/libyaml/doc/html/functions_vars_0x6c.html new file mode 100644 index 00000000..ea1e75f8 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x6c.html @@ -0,0 +1,120 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- l -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x6d.html b/libyaml/doc/html/functions_vars_0x6d.html new file mode 100644 index 00000000..c540536c --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x6d.html @@ -0,0 +1,128 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- m -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x6e.html b/libyaml/doc/html/functions_vars_0x6e.html new file mode 100644 index 00000000..9de08b99 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x6e.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- n -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x6f.html b/libyaml/doc/html/functions_vars_0x6f.html new file mode 100644 index 00000000..436fcd0b --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x6f.html @@ -0,0 +1,112 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- o -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x70.html b/libyaml/doc/html/functions_vars_0x70.html new file mode 100644 index 00000000..cc1ef49f --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x70.html @@ -0,0 +1,132 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- p -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x71.html b/libyaml/doc/html/functions_vars_0x71.html new file mode 100644 index 00000000..d9e18208 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x71.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- q -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x72.html b/libyaml/doc/html/functions_vars_0x72.html new file mode 100644 index 00000000..09cf76f2 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x72.html @@ -0,0 +1,119 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- r -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x73.html b/libyaml/doc/html/functions_vars_0x73.html new file mode 100644 index 00000000..4e82a759 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x73.html @@ -0,0 +1,195 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- s -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x74.html b/libyaml/doc/html/functions_vars_0x74.html new file mode 100644 index 00000000..ffcf1c30 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x74.html @@ -0,0 +1,147 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- t -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x75.html b/libyaml/doc/html/functions_vars_0x75.html new file mode 100644 index 00000000..51315be6 --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x75.html @@ -0,0 +1,103 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- u -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x76.html b/libyaml/doc/html/functions_vars_0x76.html new file mode 100644 index 00000000..1321cd8a --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x76.html @@ -0,0 +1,112 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- v -

+
+ + + + + + diff --git a/libyaml/doc/html/functions_vars_0x77.html b/libyaml/doc/html/functions_vars_0x77.html new file mode 100644 index 00000000..a19bbb0a --- /dev/null +++ b/libyaml/doc/html/functions_vars_0x77.html @@ -0,0 +1,109 @@ + + + + + +yaml: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- w -

+
+ + + + + + diff --git a/libyaml/doc/html/globals.html b/libyaml/doc/html/globals.html new file mode 100644 index 00000000..d51d801b --- /dev/null +++ b/libyaml/doc/html/globals.html @@ -0,0 +1,699 @@ + + + + + +yaml: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- y -

    +
  • yaml_alias_data_t +: yaml.h +
  • +
  • YAML_ALIAS_EVENT +: yaml.h +
  • +
  • yaml_alias_event_initialize() +: yaml.h +
  • +
  • YAML_ALIAS_TOKEN +: yaml.h +
  • +
  • YAML_ANCHOR_TOKEN +: yaml.h +
  • +
  • YAML_ANY_BREAK +: yaml.h +
  • +
  • YAML_ANY_ENCODING +: yaml.h +
  • +
  • YAML_ANY_MAPPING_STYLE +: yaml.h +
  • +
  • YAML_ANY_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_ANY_SEQUENCE_STYLE +: yaml.h +
  • +
  • YAML_BLOCK_END_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_ENTRY_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_MAPPING_START_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_MAPPING_STYLE +: yaml.h +
  • +
  • YAML_BLOCK_SEQUENCE_START_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_SEQUENCE_STYLE +: yaml.h +
  • +
  • YAML_BOOL_TAG +: yaml.h +
  • +
  • yaml_break_e +: yaml.h +
  • +
  • yaml_break_t +: yaml.h +
  • +
  • yaml_char_t +: yaml.h +
  • +
  • YAML_COMPOSER_ERROR +: yaml.h +
  • +
  • YAML_CR_BREAK +: yaml.h +
  • +
  • YAML_CRLN_BREAK +: yaml.h +
  • +
  • YAML_DECLARE +: yaml.h +
  • +
  • YAML_DEFAULT_MAPPING_TAG +: yaml.h +
  • +
  • YAML_DEFAULT_SCALAR_TAG +: yaml.h +
  • +
  • YAML_DEFAULT_SEQUENCE_TAG +: yaml.h +
  • +
  • yaml_document_add_mapping() +: yaml.h +
  • +
  • yaml_document_add_scalar() +: yaml.h +
  • +
  • yaml_document_add_sequence() +: yaml.h +
  • +
  • yaml_document_append_mapping_pair() +: yaml.h +
  • +
  • yaml_document_append_sequence_item() +: yaml.h +
  • +
  • yaml_document_delete() +: yaml.h +
  • +
  • YAML_DOCUMENT_END_EVENT +: yaml.h +
  • +
  • yaml_document_end_event_initialize() +: yaml.h +
  • +
  • YAML_DOCUMENT_END_TOKEN +: yaml.h +
  • +
  • yaml_document_get_node() +: yaml.h +
  • +
  • yaml_document_get_root_node() +: yaml.h +
  • +
  • yaml_document_initialize() +: yaml.h +
  • +
  • YAML_DOCUMENT_START_EVENT +: yaml.h +
  • +
  • yaml_document_start_event_initialize() +: yaml.h +
  • +
  • YAML_DOCUMENT_START_TOKEN +: yaml.h +
  • +
  • yaml_document_t +: yaml.h +
  • +
  • YAML_DOUBLE_QUOTED_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_DOCUMENT_CONTENT_STATE +: yaml.h +
  • +
  • YAML_EMIT_DOCUMENT_END_STATE +: yaml.h +
  • +
  • YAML_EMIT_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_EMIT_END_STATE +: yaml.h +
  • +
  • YAML_EMIT_FIRST_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_STREAM_START_STATE +: yaml.h +
  • +
  • yaml_emitter_close() +: yaml.h +
  • +
  • yaml_emitter_delete() +: yaml.h +
  • +
  • yaml_emitter_dump() +: yaml.h +
  • +
  • yaml_emitter_emit() +: yaml.h +
  • +
  • YAML_EMITTER_ERROR +: yaml.h +
  • +
  • yaml_emitter_flush() +: yaml.h +
  • +
  • yaml_emitter_initialize() +: yaml.h +
  • +
  • yaml_emitter_open() +: yaml.h +
  • +
  • yaml_emitter_set_break() +: yaml.h +
  • +
  • yaml_emitter_set_canonical() +: yaml.h +
  • +
  • yaml_emitter_set_encoding() +: yaml.h +
  • +
  • yaml_emitter_set_indent() +: yaml.h +
  • +
  • yaml_emitter_set_output() +: yaml.h +
  • +
  • yaml_emitter_set_output_file() +: yaml.h +
  • +
  • yaml_emitter_set_output_string() +: yaml.h +
  • +
  • yaml_emitter_set_unicode() +: yaml.h +
  • +
  • yaml_emitter_set_width() +: yaml.h +
  • +
  • yaml_emitter_state_e +: yaml.h +
  • +
  • yaml_emitter_state_t +: yaml.h +
  • +
  • yaml_emitter_t +: yaml.h +
  • +
  • yaml_encoding_e +: yaml.h +
  • +
  • yaml_encoding_t +: yaml.h +
  • +
  • yaml_error_type_e +: yaml.h +
  • +
  • yaml_error_type_t +: yaml.h +
  • +
  • yaml_event_delete() +: yaml.h +
  • +
  • yaml_event_t +: yaml.h +
  • +
  • yaml_event_type_e +: yaml.h +
  • +
  • yaml_event_type_t +: yaml.h +
  • +
  • YAML_FLOAT_TAG +: yaml.h +
  • +
  • YAML_FLOW_ENTRY_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_MAPPING_END_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_MAPPING_START_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_MAPPING_STYLE +: yaml.h +
  • +
  • YAML_FLOW_SEQUENCE_END_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_SEQUENCE_START_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_SEQUENCE_STYLE +: yaml.h +
  • +
  • YAML_FOLDED_SCALAR_STYLE +: yaml.h +
  • +
  • yaml_get_version() +: yaml.h +
  • +
  • yaml_get_version_string() +: yaml.h +
  • +
  • YAML_INT_TAG +: yaml.h +
  • +
  • YAML_KEY_TOKEN +: yaml.h +
  • +
  • YAML_LITERAL_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_LN_BREAK +: yaml.h +
  • +
  • YAML_MAP_TAG +: yaml.h +
  • +
  • YAML_MAPPING_END_EVENT +: yaml.h +
  • +
  • yaml_mapping_end_event_initialize() +: yaml.h +
  • +
  • YAML_MAPPING_NODE +: yaml.h +
  • +
  • YAML_MAPPING_START_EVENT +: yaml.h +
  • +
  • yaml_mapping_start_event_initialize() +: yaml.h +
  • +
  • yaml_mapping_style_e +: yaml.h +
  • +
  • yaml_mapping_style_t +: yaml.h +
  • +
  • yaml_mark_t +: yaml.h +
  • +
  • YAML_MEMORY_ERROR +: yaml.h +
  • +
  • YAML_NO_ERROR +: yaml.h +
  • +
  • YAML_NO_EVENT +: yaml.h +
  • +
  • YAML_NO_NODE +: yaml.h +
  • +
  • YAML_NO_TOKEN +: yaml.h +
  • +
  • yaml_node_item_t +: yaml.h +
  • +
  • yaml_node_pair_t +: yaml.h +
  • +
  • yaml_node_t +: yaml.h +
  • +
  • yaml_node_type_e +: yaml.h +
  • +
  • yaml_node_type_t +: yaml.h +
  • +
  • YAML_NULL_TAG +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_NODE_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_DOCUMENT_CONTENT_STATE +: yaml.h +
  • +
  • YAML_PARSE_DOCUMENT_END_STATE +: yaml.h +
  • +
  • YAML_PARSE_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_PARSE_END_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_NODE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_STREAM_START_STATE +: yaml.h +
  • +
  • yaml_parser_delete() +: yaml.h +
  • +
  • YAML_PARSER_ERROR +: yaml.h +
  • +
  • yaml_parser_initialize() +: yaml.h +
  • +
  • yaml_parser_load() +: yaml.h +
  • +
  • yaml_parser_parse() +: yaml.h +
  • +
  • yaml_parser_scan() +: yaml.h +
  • +
  • yaml_parser_set_encoding() +: yaml.h +
  • +
  • yaml_parser_set_input() +: yaml.h +
  • +
  • yaml_parser_set_input_file() +: yaml.h +
  • +
  • yaml_parser_set_input_string() +: yaml.h +
  • +
  • yaml_parser_state_e +: yaml.h +
  • +
  • yaml_parser_state_t +: yaml.h +
  • +
  • yaml_parser_t +: yaml.h +
  • +
  • YAML_PLAIN_SCALAR_STYLE +: yaml.h +
  • +
  • yaml_read_handler_t +: yaml.h +
  • +
  • YAML_READER_ERROR +: yaml.h +
  • +
  • YAML_SCALAR_EVENT +: yaml.h +
  • +
  • yaml_scalar_event_initialize() +: yaml.h +
  • +
  • YAML_SCALAR_NODE +: yaml.h +
  • +
  • yaml_scalar_style_e +: yaml.h +
  • +
  • yaml_scalar_style_t +: yaml.h +
  • +
  • YAML_SCALAR_TOKEN +: yaml.h +
  • +
  • YAML_SCANNER_ERROR +: yaml.h +
  • +
  • YAML_SEQ_TAG +: yaml.h +
  • +
  • YAML_SEQUENCE_END_EVENT +: yaml.h +
  • +
  • yaml_sequence_end_event_initialize() +: yaml.h +
  • +
  • YAML_SEQUENCE_NODE +: yaml.h +
  • +
  • YAML_SEQUENCE_START_EVENT +: yaml.h +
  • +
  • yaml_sequence_start_event_initialize() +: yaml.h +
  • +
  • yaml_sequence_style_e +: yaml.h +
  • +
  • yaml_sequence_style_t +: yaml.h +
  • +
  • yaml_simple_key_t +: yaml.h +
  • +
  • YAML_SINGLE_QUOTED_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_STR_TAG +: yaml.h +
  • +
  • YAML_STREAM_END_EVENT +: yaml.h +
  • +
  • yaml_stream_end_event_initialize() +: yaml.h +
  • +
  • YAML_STREAM_END_TOKEN +: yaml.h +
  • +
  • YAML_STREAM_START_EVENT +: yaml.h +
  • +
  • yaml_stream_start_event_initialize() +: yaml.h +
  • +
  • YAML_STREAM_START_TOKEN +: yaml.h +
  • +
  • yaml_tag_directive_t +: yaml.h +
  • +
  • YAML_TAG_DIRECTIVE_TOKEN +: yaml.h +
  • +
  • YAML_TAG_TOKEN +: yaml.h +
  • +
  • YAML_TIMESTAMP_TAG +: yaml.h +
  • +
  • yaml_token_delete() +: yaml.h +
  • +
  • yaml_token_t +: yaml.h +
  • +
  • yaml_token_type_e +: yaml.h +
  • +
  • yaml_token_type_t +: yaml.h +
  • +
  • YAML_UTF16BE_ENCODING +: yaml.h +
  • +
  • YAML_UTF16LE_ENCODING +: yaml.h +
  • +
  • YAML_UTF8_ENCODING +: yaml.h +
  • +
  • YAML_VALUE_TOKEN +: yaml.h +
  • +
  • yaml_version_directive_t +: yaml.h +
  • +
  • YAML_VERSION_DIRECTIVE_TOKEN +: yaml.h +
  • +
  • yaml_write_handler_t +: yaml.h +
  • +
  • YAML_WRITER_ERROR +: yaml.h +
  • +
+
+ + + + + + diff --git a/libyaml/doc/html/globals_defs.html b/libyaml/doc/html/globals_defs.html new file mode 100644 index 00000000..84525318 --- /dev/null +++ b/libyaml/doc/html/globals_defs.html @@ -0,0 +1,113 @@ + + + + + +yaml: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + +
+
    +
  • YAML_BOOL_TAG +: yaml.h +
  • +
  • YAML_DECLARE +: yaml.h +
  • +
  • YAML_DEFAULT_MAPPING_TAG +: yaml.h +
  • +
  • YAML_DEFAULT_SCALAR_TAG +: yaml.h +
  • +
  • YAML_DEFAULT_SEQUENCE_TAG +: yaml.h +
  • +
  • YAML_FLOAT_TAG +: yaml.h +
  • +
  • YAML_INT_TAG +: yaml.h +
  • +
  • YAML_MAP_TAG +: yaml.h +
  • +
  • YAML_NULL_TAG +: yaml.h +
  • +
  • YAML_SEQ_TAG +: yaml.h +
  • +
  • YAML_STR_TAG +: yaml.h +
  • +
  • YAML_TIMESTAMP_TAG +: yaml.h +
  • +
+
+ + + + + + diff --git a/libyaml/doc/html/globals_enum.html b/libyaml/doc/html/globals_enum.html new file mode 100644 index 00000000..12ab0b53 --- /dev/null +++ b/libyaml/doc/html/globals_enum.html @@ -0,0 +1,110 @@ + + + + + +yaml: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + +
+
    +
  • yaml_break_e +: yaml.h +
  • +
  • yaml_emitter_state_e +: yaml.h +
  • +
  • yaml_encoding_e +: yaml.h +
  • +
  • yaml_error_type_e +: yaml.h +
  • +
  • yaml_event_type_e +: yaml.h +
  • +
  • yaml_mapping_style_e +: yaml.h +
  • +
  • yaml_node_type_e +: yaml.h +
  • +
  • yaml_parser_state_e +: yaml.h +
  • +
  • yaml_scalar_style_e +: yaml.h +
  • +
  • yaml_sequence_style_e +: yaml.h +
  • +
  • yaml_token_type_e +: yaml.h +
  • +
+
+ + + + + + diff --git a/libyaml/doc/html/globals_eval.html b/libyaml/doc/html/globals_eval.html new file mode 100644 index 00000000..0d4ef5e5 --- /dev/null +++ b/libyaml/doc/html/globals_eval.html @@ -0,0 +1,405 @@ + + + + + +yaml: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- y -

    +
  • YAML_ALIAS_EVENT +: yaml.h +
  • +
  • YAML_ALIAS_TOKEN +: yaml.h +
  • +
  • YAML_ANCHOR_TOKEN +: yaml.h +
  • +
  • YAML_ANY_BREAK +: yaml.h +
  • +
  • YAML_ANY_ENCODING +: yaml.h +
  • +
  • YAML_ANY_MAPPING_STYLE +: yaml.h +
  • +
  • YAML_ANY_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_ANY_SEQUENCE_STYLE +: yaml.h +
  • +
  • YAML_BLOCK_END_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_ENTRY_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_MAPPING_START_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_MAPPING_STYLE +: yaml.h +
  • +
  • YAML_BLOCK_SEQUENCE_START_TOKEN +: yaml.h +
  • +
  • YAML_BLOCK_SEQUENCE_STYLE +: yaml.h +
  • +
  • YAML_COMPOSER_ERROR +: yaml.h +
  • +
  • YAML_CR_BREAK +: yaml.h +
  • +
  • YAML_CRLN_BREAK +: yaml.h +
  • +
  • YAML_DOCUMENT_END_EVENT +: yaml.h +
  • +
  • YAML_DOCUMENT_END_TOKEN +: yaml.h +
  • +
  • YAML_DOCUMENT_START_EVENT +: yaml.h +
  • +
  • YAML_DOCUMENT_START_TOKEN +: yaml.h +
  • +
  • YAML_DOUBLE_QUOTED_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_DOCUMENT_CONTENT_STATE +: yaml.h +
  • +
  • YAML_EMIT_DOCUMENT_END_STATE +: yaml.h +
  • +
  • YAML_EMIT_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_EMIT_END_STATE +: yaml.h +
  • +
  • YAML_EMIT_FIRST_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE +: yaml.h +
  • +
  • YAML_EMIT_STREAM_START_STATE +: yaml.h +
  • +
  • YAML_EMITTER_ERROR +: yaml.h +
  • +
  • YAML_FLOW_ENTRY_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_MAPPING_END_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_MAPPING_START_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_MAPPING_STYLE +: yaml.h +
  • +
  • YAML_FLOW_SEQUENCE_END_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_SEQUENCE_START_TOKEN +: yaml.h +
  • +
  • YAML_FLOW_SEQUENCE_STYLE +: yaml.h +
  • +
  • YAML_FOLDED_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_KEY_TOKEN +: yaml.h +
  • +
  • YAML_LITERAL_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_LN_BREAK +: yaml.h +
  • +
  • YAML_MAPPING_END_EVENT +: yaml.h +
  • +
  • YAML_MAPPING_NODE +: yaml.h +
  • +
  • YAML_MAPPING_START_EVENT +: yaml.h +
  • +
  • YAML_MEMORY_ERROR +: yaml.h +
  • +
  • YAML_NO_ERROR +: yaml.h +
  • +
  • YAML_NO_EVENT +: yaml.h +
  • +
  • YAML_NO_NODE +: yaml.h +
  • +
  • YAML_NO_TOKEN +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_NODE_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_DOCUMENT_CONTENT_STATE +: yaml.h +
  • +
  • YAML_PARSE_DOCUMENT_END_STATE +: yaml.h +
  • +
  • YAML_PARSE_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_PARSE_END_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_NODE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE +: yaml.h +
  • +
  • YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE +: yaml.h +
  • +
  • YAML_PARSE_STREAM_START_STATE +: yaml.h +
  • +
  • YAML_PARSER_ERROR +: yaml.h +
  • +
  • YAML_PLAIN_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_READER_ERROR +: yaml.h +
  • +
  • YAML_SCALAR_EVENT +: yaml.h +
  • +
  • YAML_SCALAR_NODE +: yaml.h +
  • +
  • YAML_SCALAR_TOKEN +: yaml.h +
  • +
  • YAML_SCANNER_ERROR +: yaml.h +
  • +
  • YAML_SEQUENCE_END_EVENT +: yaml.h +
  • +
  • YAML_SEQUENCE_NODE +: yaml.h +
  • +
  • YAML_SEQUENCE_START_EVENT +: yaml.h +
  • +
  • YAML_SINGLE_QUOTED_SCALAR_STYLE +: yaml.h +
  • +
  • YAML_STREAM_END_EVENT +: yaml.h +
  • +
  • YAML_STREAM_END_TOKEN +: yaml.h +
  • +
  • YAML_STREAM_START_EVENT +: yaml.h +
  • +
  • YAML_STREAM_START_TOKEN +: yaml.h +
  • +
  • YAML_TAG_DIRECTIVE_TOKEN +: yaml.h +
  • +
  • YAML_TAG_TOKEN +: yaml.h +
  • +
  • YAML_UTF16BE_ENCODING +: yaml.h +
  • +
  • YAML_UTF16LE_ENCODING +: yaml.h +
  • +
  • YAML_UTF8_ENCODING +: yaml.h +
  • +
  • YAML_VALUE_TOKEN +: yaml.h +
  • +
  • YAML_VERSION_DIRECTIVE_TOKEN +: yaml.h +
  • +
  • YAML_WRITER_ERROR +: yaml.h +
  • +
+
+ + + + + + diff --git a/libyaml/doc/html/globals_func.html b/libyaml/doc/html/globals_func.html new file mode 100644 index 00000000..c9da4033 --- /dev/null +++ b/libyaml/doc/html/globals_func.html @@ -0,0 +1,228 @@ + + + + + +yaml: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + + +
+
+  + +

- y -

    +
  • yaml_alias_event_initialize() +: yaml.h +
  • +
  • yaml_document_add_mapping() +: yaml.h +
  • +
  • yaml_document_add_scalar() +: yaml.h +
  • +
  • yaml_document_add_sequence() +: yaml.h +
  • +
  • yaml_document_append_mapping_pair() +: yaml.h +
  • +
  • yaml_document_append_sequence_item() +: yaml.h +
  • +
  • yaml_document_delete() +: yaml.h +
  • +
  • yaml_document_end_event_initialize() +: yaml.h +
  • +
  • yaml_document_get_node() +: yaml.h +
  • +
  • yaml_document_get_root_node() +: yaml.h +
  • +
  • yaml_document_initialize() +: yaml.h +
  • +
  • yaml_document_start_event_initialize() +: yaml.h +
  • +
  • yaml_emitter_close() +: yaml.h +
  • +
  • yaml_emitter_delete() +: yaml.h +
  • +
  • yaml_emitter_dump() +: yaml.h +
  • +
  • yaml_emitter_emit() +: yaml.h +
  • +
  • yaml_emitter_flush() +: yaml.h +
  • +
  • yaml_emitter_initialize() +: yaml.h +
  • +
  • yaml_emitter_open() +: yaml.h +
  • +
  • yaml_emitter_set_break() +: yaml.h +
  • +
  • yaml_emitter_set_canonical() +: yaml.h +
  • +
  • yaml_emitter_set_encoding() +: yaml.h +
  • +
  • yaml_emitter_set_indent() +: yaml.h +
  • +
  • yaml_emitter_set_output() +: yaml.h +
  • +
  • yaml_emitter_set_output_file() +: yaml.h +
  • +
  • yaml_emitter_set_output_string() +: yaml.h +
  • +
  • yaml_emitter_set_unicode() +: yaml.h +
  • +
  • yaml_emitter_set_width() +: yaml.h +
  • +
  • yaml_event_delete() +: yaml.h +
  • +
  • yaml_get_version() +: yaml.h +
  • +
  • yaml_get_version_string() +: yaml.h +
  • +
  • yaml_mapping_end_event_initialize() +: yaml.h +
  • +
  • yaml_mapping_start_event_initialize() +: yaml.h +
  • +
  • yaml_parser_delete() +: yaml.h +
  • +
  • yaml_parser_initialize() +: yaml.h +
  • +
  • yaml_parser_load() +: yaml.h +
  • +
  • yaml_parser_parse() +: yaml.h +
  • +
  • yaml_parser_scan() +: yaml.h +
  • +
  • yaml_parser_set_encoding() +: yaml.h +
  • +
  • yaml_parser_set_input() +: yaml.h +
  • +
  • yaml_parser_set_input_file() +: yaml.h +
  • +
  • yaml_parser_set_input_string() +: yaml.h +
  • +
  • yaml_scalar_event_initialize() +: yaml.h +
  • +
  • yaml_sequence_end_event_initialize() +: yaml.h +
  • +
  • yaml_sequence_start_event_initialize() +: yaml.h +
  • +
  • yaml_stream_end_event_initialize() +: yaml.h +
  • +
  • yaml_stream_start_event_initialize() +: yaml.h +
  • +
  • yaml_token_delete() +: yaml.h +
  • +
+
+ + + + + + diff --git a/libyaml/doc/html/globals_type.html b/libyaml/doc/html/globals_type.html new file mode 100644 index 00000000..7e7e2a0e --- /dev/null +++ b/libyaml/doc/html/globals_type.html @@ -0,0 +1,158 @@ + + + + + +yaml: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + + +
+
    +
  • yaml_alias_data_t +: yaml.h +
  • +
  • yaml_break_t +: yaml.h +
  • +
  • yaml_char_t +: yaml.h +
  • +
  • yaml_document_t +: yaml.h +
  • +
  • yaml_emitter_state_t +: yaml.h +
  • +
  • yaml_emitter_t +: yaml.h +
  • +
  • yaml_encoding_t +: yaml.h +
  • +
  • yaml_error_type_t +: yaml.h +
  • +
  • yaml_event_t +: yaml.h +
  • +
  • yaml_event_type_t +: yaml.h +
  • +
  • yaml_mapping_style_t +: yaml.h +
  • +
  • yaml_mark_t +: yaml.h +
  • +
  • yaml_node_item_t +: yaml.h +
  • +
  • yaml_node_pair_t +: yaml.h +
  • +
  • yaml_node_t +: yaml.h +
  • +
  • yaml_node_type_t +: yaml.h +
  • +
  • yaml_parser_state_t +: yaml.h +
  • +
  • yaml_parser_t +: yaml.h +
  • +
  • yaml_read_handler_t +: yaml.h +
  • +
  • yaml_scalar_style_t +: yaml.h +
  • +
  • yaml_sequence_style_t +: yaml.h +
  • +
  • yaml_simple_key_t +: yaml.h +
  • +
  • yaml_tag_directive_t +: yaml.h +
  • +
  • yaml_token_t +: yaml.h +
  • +
  • yaml_token_type_t +: yaml.h +
  • +
  • yaml_version_directive_t +: yaml.h +
  • +
  • yaml_write_handler_t +: yaml.h +
  • +
+
+ + + + + + diff --git a/libyaml/doc/html/group__basic.html b/libyaml/doc/html/group__basic.html new file mode 100644 index 00000000..f8f38106 --- /dev/null +++ b/libyaml/doc/html/group__basic.html @@ -0,0 +1,349 @@ + + + + + +yaml: Basic Types + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+ +
+
Basic Types
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_version_directive_s
 The version directive data. More...
struct  yaml_tag_directive_s
 The tag directive data. More...
struct  yaml_mark_s
 The pointer position. More...

+Typedefs

typedef unsigned char yaml_char_t
 The character type (UTF-8 octet).
typedef struct
+yaml_version_directive_s 
yaml_version_directive_t
 The version directive data.
typedef struct yaml_tag_directive_s yaml_tag_directive_t
 The tag directive data.
typedef enum yaml_encoding_e yaml_encoding_t
 The stream encoding.
typedef enum yaml_break_e yaml_break_t
 Line break types.
typedef enum yaml_error_type_e yaml_error_type_t
 Many bad things could happen with the parser and emitter.
typedef struct yaml_mark_s yaml_mark_t
 The pointer position.

+Enumerations

enum  yaml_encoding_e {
+  YAML_ANY_ENCODING, +
+  YAML_UTF8_ENCODING, +
+  YAML_UTF16LE_ENCODING, +
+  YAML_UTF16BE_ENCODING +
+ }
 The stream encoding. More...
enum  yaml_break_e {
+  YAML_ANY_BREAK, +
+  YAML_CR_BREAK, +
+  YAML_LN_BREAK, +
+  YAML_CRLN_BREAK +
+ }
 Line break types. More...
enum  yaml_error_type_e {
+  YAML_NO_ERROR, +
+  YAML_MEMORY_ERROR, +
+  YAML_READER_ERROR, +
+  YAML_SCANNER_ERROR, +
+  YAML_PARSER_ERROR, +
+  YAML_COMPOSER_ERROR, +
+  YAML_WRITER_ERROR, +
+  YAML_EMITTER_ERROR +
+ }
 Many bad things could happen with the parser and emitter. More...
+

Typedef Documentation

+ +
+
+ + + + +
typedef unsigned char yaml_char_t
+
+
+ +

The character type (UTF-8 octet).

+ +
+
+ +
+ +
+ +

The version directive data.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_tag_directive_s yaml_tag_directive_t
+
+
+ +

The tag directive data.

+ +
+
+ +
+
+ + + + +
typedef enum yaml_encoding_e yaml_encoding_t
+
+
+ +

The stream encoding.

+ +
+
+ +
+
+ + + + +
typedef enum yaml_break_e yaml_break_t
+
+
+ +

Line break types.

+ +
+
+ +
+
+ + + + +
typedef enum yaml_error_type_e yaml_error_type_t
+
+
+ +

Many bad things could happen with the parser and emitter.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_mark_s yaml_mark_t
+
+
+ +

The pointer position.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_encoding_e
+
+
+ +

The stream encoding.

+
Enumerator:
+ + + + +
YAML_ANY_ENCODING  +

Let the parser choose the encoding.

+
YAML_UTF8_ENCODING  +

The default UTF-8 encoding.

+
YAML_UTF16LE_ENCODING  +

The UTF-16-LE encoding with BOM.

+
YAML_UTF16BE_ENCODING  +

The UTF-16-BE encoding with BOM.

+
+
+
+ +
+
+ +
+
+ + + + +
enum yaml_break_e
+
+
+ +

Line break types.

+
Enumerator:
+ + + + +
YAML_ANY_BREAK  +

Let the parser choose the break type.

+
YAML_CR_BREAK  +

Use CR for line breaks (Mac style).

+
YAML_LN_BREAK  +

Use LN for line breaks (Unix style).

+
YAML_CRLN_BREAK  +

Use CR LN for line breaks (DOS style).

+
+
+
+ +
+
+ +
+
+ + + + +
enum yaml_error_type_e
+
+
+ +

Many bad things could happen with the parser and emitter.

+
Enumerator:
+ + + + + + + + +
YAML_NO_ERROR  +

No error is produced.

+
YAML_MEMORY_ERROR  +

Cannot allocate or reallocate a block of memory.

+
YAML_READER_ERROR  +

Cannot read or decode the input stream.

+
YAML_SCANNER_ERROR  +

Cannot scan the input stream.

+
YAML_PARSER_ERROR  +

Cannot parse the input stream.

+
YAML_COMPOSER_ERROR  +

Cannot compose a YAML document.

+
YAML_WRITER_ERROR  +

Cannot write to the output stream.

+
YAML_EMITTER_ERROR  +

Cannot emit a YAML stream.

+
+
+
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__emitter.html b/libyaml/doc/html/group__emitter.html new file mode 100644 index 00000000..162a93f1 --- /dev/null +++ b/libyaml/doc/html/group__emitter.html @@ -0,0 +1,845 @@ + + + + + +yaml: Emitter Definitions + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+ +
+
Emitter Definitions
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_emitter_s
 The emitter structure. More...

+Typedefs

typedef int yaml_write_handler_t (void *data, unsigned char *buffer, size_t size)
 The prototype of a write handler.
typedef enum yaml_emitter_state_e yaml_emitter_state_t
 The emitter states.
typedef struct yaml_emitter_s yaml_emitter_t
 The emitter structure.

+Enumerations

enum  yaml_emitter_state_e {
+  YAML_EMIT_STREAM_START_STATE, +
+  YAML_EMIT_FIRST_DOCUMENT_START_STATE, +
+  YAML_EMIT_DOCUMENT_START_STATE, +
+  YAML_EMIT_DOCUMENT_CONTENT_STATE, +
+  YAML_EMIT_DOCUMENT_END_STATE, +
+  YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, +
+  YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, +
+  YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, +
+  YAML_EMIT_FLOW_MAPPING_KEY_STATE, +
+  YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, +
+  YAML_EMIT_FLOW_MAPPING_VALUE_STATE, +
+  YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, +
+  YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_KEY_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, +
+  YAML_EMIT_END_STATE +
+ }
 The emitter states. More...

+Functions

int yaml_emitter_initialize (yaml_emitter_t *emitter)
 Initialize an emitter.
void yaml_emitter_delete (yaml_emitter_t *emitter)
 Destroy an emitter.
void yaml_emitter_set_output_string (yaml_emitter_t *emitter, unsigned char *output, size_t size, size_t *size_written)
 Set a string output.
void yaml_emitter_set_output_file (yaml_emitter_t *emitter, FILE *file)
 Set a file output.
void yaml_emitter_set_output (yaml_emitter_t *emitter, yaml_write_handler_t *handler, void *data)
 Set a generic output handler.
void yaml_emitter_set_encoding (yaml_emitter_t *emitter, yaml_encoding_t encoding)
 Set the output encoding.
void yaml_emitter_set_canonical (yaml_emitter_t *emitter, int canonical)
 Set if the output should be in the "canonical" format as in the YAML specification.
void yaml_emitter_set_indent (yaml_emitter_t *emitter, int indent)
 Set the intendation increment.
void yaml_emitter_set_width (yaml_emitter_t *emitter, int width)
 Set the preferred line width.
void yaml_emitter_set_unicode (yaml_emitter_t *emitter, int unicode)
 Set if unescaped non-ASCII characters are allowed.
void yaml_emitter_set_break (yaml_emitter_t *emitter, yaml_break_t line_break)
 Set the preferred line break.
int yaml_emitter_emit (yaml_emitter_t *emitter, yaml_event_t *event)
 Emit an event.
int yaml_emitter_open (yaml_emitter_t *emitter)
 Start a YAML stream.
int yaml_emitter_close (yaml_emitter_t *emitter)
 Finish a YAML stream.
int yaml_emitter_dump (yaml_emitter_t *emitter, yaml_document_t *document)
 Emit a YAML document.
int yaml_emitter_flush (yaml_emitter_t *emitter)
 Flush the accumulated characters to the output.
+

Typedef Documentation

+ +
+
+ + + + +
typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size)
+
+
+ +

The prototype of a write handler.

+

The write handler is called when the emitter needs to flush the accumulated characters to the output. The handler should write size bytes of the buffer to the output.

+
Parameters:
+ + + + +
[in,out]dataA pointer to an application data specified by yaml_emitter_set_output().
[in]bufferThe buffer with bytes to be written.
[in]sizeThe size of the buffer.
+
+
+
Returns:
On success, the handler should return 1. If the handler failed, the returned value should be 0.
+ +
+
+ +
+
+ + + + +
typedef enum yaml_emitter_state_e yaml_emitter_state_t
+
+
+ +

The emitter states.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_emitter_s yaml_emitter_t
+
+
+ +

The emitter structure.

+

All members are internal. Manage the structure using the yaml_emitter_ family of functions.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_emitter_state_e
+
+
+ +

The emitter states.

+
Enumerator:
+ + + + + + + + + + + + + + + + + + +
YAML_EMIT_STREAM_START_STATE  +

Expect STREAM-START.

+
YAML_EMIT_FIRST_DOCUMENT_START_STATE  +

Expect the first DOCUMENT-START or STREAM-END.

+
YAML_EMIT_DOCUMENT_START_STATE  +

Expect DOCUMENT-START or STREAM-END.

+
YAML_EMIT_DOCUMENT_CONTENT_STATE  +

Expect the content of a document.

+
YAML_EMIT_DOCUMENT_END_STATE  +

Expect DOCUMENT-END.

+
YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE  +

Expect the first item of a flow sequence.

+
YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE  +

Expect an item of a flow sequence.

+
YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE  +

Expect the first key of a flow mapping.

+
YAML_EMIT_FLOW_MAPPING_KEY_STATE  +

Expect a key of a flow mapping.

+
YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE  +

Expect a value for a simple key of a flow mapping.

+
YAML_EMIT_FLOW_MAPPING_VALUE_STATE  +

Expect a value of a flow mapping.

+
YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE  +

Expect the first item of a block sequence.

+
YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE  +

Expect an item of a block sequence.

+
YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE  +

Expect the first key of a block mapping.

+
YAML_EMIT_BLOCK_MAPPING_KEY_STATE  +

Expect the key of a block mapping.

+
YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE  +

Expect a value for a simple key of a block mapping.

+
YAML_EMIT_BLOCK_MAPPING_VALUE_STATE  +

Expect a value of a block mapping.

+
YAML_EMIT_END_STATE  +

Expect nothing.

+
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
int yaml_emitter_initialize (yaml_emitter_temitter)
+
+
+ +

Initialize an emitter.

+

This function creates a new emitter object. An application is responsible for destroying the object using the yaml_emitter_delete() function.

+
Parameters:
+ + +
[out]emitterAn empty parser object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
void yaml_emitter_delete (yaml_emitter_temitter)
+
+
+ +

Destroy an emitter.

+
Parameters:
+ + +
[in,out]emitterAn emitter object.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_output_string (yaml_emitter_temitter,
unsigned char * output,
size_t size,
size_t * size_written 
)
+
+
+ +

Set a string output.

+

The emitter will write the output characters to the output buffer of the size size. The emitter will set size_written to the number of written bytes. If the buffer is smaller than required, the emitter produces the YAML_WRITE_ERROR error.

+
Parameters:
+ + + + + +
[in,out]emitterAn emitter object.
[in]outputAn output buffer.
[in]sizeThe buffer size.
[in]size_writtenThe pointer to save the number of written bytes.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_output_file (yaml_emitter_temitter,
FILE * file 
)
+
+
+ +

Set a file output.

+

file should be a file object open for writing. The application is responsible for closing the file.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]fileAn open file.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_output (yaml_emitter_temitter,
yaml_write_handler_thandler,
void * data 
)
+
+
+ +

Set a generic output handler.

+
Parameters:
+ + + + +
[in,out]emitterAn emitter object.
[in]handlerA write handler.
[in]dataAny application data for passing to the write handler.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_encoding (yaml_emitter_temitter,
yaml_encoding_t encoding 
)
+
+
+ +

Set the output encoding.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]encodingThe output encoding.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_canonical (yaml_emitter_temitter,
int canonical 
)
+
+
+ +

Set if the output should be in the "canonical" format as in the YAML specification.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]canonicalIf the output is canonical.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_indent (yaml_emitter_temitter,
int indent 
)
+
+
+ +

Set the intendation increment.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]indentThe indentation increment (1 < . < 10).
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_width (yaml_emitter_temitter,
int width 
)
+
+
+ +

Set the preferred line width.

+

-1 means unlimited.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]widthThe preferred line width.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_unicode (yaml_emitter_temitter,
int unicode 
)
+
+
+ +

Set if unescaped non-ASCII characters are allowed.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]unicodeIf unescaped Unicode characters are allowed.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_emitter_set_break (yaml_emitter_temitter,
yaml_break_t line_break 
)
+
+
+ +

Set the preferred line break.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in]line_breakThe preferred line break.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_emitter_emit (yaml_emitter_temitter,
yaml_event_tevent 
)
+
+
+ +

Emit an event.

+

The event object may be generated using the yaml_parser_parse() function. The emitter takes the responsibility for the event object and destroys its content after it is emitted. The event object is destroyed even if the function fails.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in,out]eventAn event object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
int yaml_emitter_open (yaml_emitter_temitter)
+
+
+ +

Start a YAML stream.

+

This function should be used before yaml_emitter_dump() is called.

+
Parameters:
+ + +
[in,out]emitterAn emitter object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
int yaml_emitter_close (yaml_emitter_temitter)
+
+
+ +

Finish a YAML stream.

+

This function should be used after yaml_emitter_dump() is called.

+
Parameters:
+ + +
[in,out]emitterAn emitter object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_emitter_dump (yaml_emitter_temitter,
yaml_document_tdocument 
)
+
+
+ +

Emit a YAML document.

+

The documen object may be generated using the yaml_parser_load() function or the yaml_document_initialize() function. The emitter takes the responsibility for the document object and destoys its content after it is emitted. The document object is destroyedeven if the function fails.

+
Parameters:
+ + + +
[in,out]emitterAn emitter object.
[in,out]documentA document object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
int yaml_emitter_flush (yaml_emitter_temitter)
+
+
+ +

Flush the accumulated characters to the output.

+
Parameters:
+ + +
[in,out]emitterAn emitter object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__events.html b/libyaml/doc/html/group__events.html new file mode 100644 index 00000000..1d10630f --- /dev/null +++ b/libyaml/doc/html/group__events.html @@ -0,0 +1,691 @@ + + + + + +yaml: Events + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_event_s
 The event structure. More...

+Typedefs

typedef enum yaml_event_type_e yaml_event_type_t
 Event types.
typedef struct yaml_event_s yaml_event_t
 The event structure.

+Enumerations

enum  yaml_event_type_e {
+  YAML_NO_EVENT, +
+  YAML_STREAM_START_EVENT, +
+  YAML_STREAM_END_EVENT, +
+  YAML_DOCUMENT_START_EVENT, +
+  YAML_DOCUMENT_END_EVENT, +
+  YAML_ALIAS_EVENT, +
+  YAML_SCALAR_EVENT, +
+  YAML_SEQUENCE_START_EVENT, +
+  YAML_SEQUENCE_END_EVENT, +
+  YAML_MAPPING_START_EVENT, +
+  YAML_MAPPING_END_EVENT +
+ }
 Event types. More...

+Functions

int yaml_stream_start_event_initialize (yaml_event_t *event, yaml_encoding_t encoding)
 Create the STREAM-START event.
int yaml_stream_end_event_initialize (yaml_event_t *event)
 Create the STREAM-END event.
int yaml_document_start_event_initialize (yaml_event_t *event, yaml_version_directive_t *version_directive, yaml_tag_directive_t *tag_directives_start, yaml_tag_directive_t *tag_directives_end, int implicit)
 Create the DOCUMENT-START event.
int yaml_document_end_event_initialize (yaml_event_t *event, int implicit)
 Create the DOCUMENT-END event.
int yaml_alias_event_initialize (yaml_event_t *event, yaml_char_t *anchor)
 Create an ALIAS event.
int yaml_scalar_event_initialize (yaml_event_t *event, yaml_char_t *anchor, yaml_char_t *tag, yaml_char_t *value, int length, int plain_implicit, int quoted_implicit, yaml_scalar_style_t style)
 Create a SCALAR event.
int yaml_sequence_start_event_initialize (yaml_event_t *event, yaml_char_t *anchor, yaml_char_t *tag, int implicit, yaml_sequence_style_t style)
 Create a SEQUENCE-START event.
int yaml_sequence_end_event_initialize (yaml_event_t *event)
 Create a SEQUENCE-END event.
int yaml_mapping_start_event_initialize (yaml_event_t *event, yaml_char_t *anchor, yaml_char_t *tag, int implicit, yaml_mapping_style_t style)
 Create a MAPPING-START event.
int yaml_mapping_end_event_initialize (yaml_event_t *event)
 Create a MAPPING-END event.
void yaml_event_delete (yaml_event_t *event)
 Free any memory allocated for an event object.
+

Typedef Documentation

+ +
+
+ + + + +
typedef enum yaml_event_type_e yaml_event_type_t
+
+
+ +

Event types.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_event_s yaml_event_t
+
+
+ +

The event structure.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_event_type_e
+
+
+ +

Event types.

+
Enumerator:
+ + + + + + + + + + + +
YAML_NO_EVENT  +

An empty event.

+
YAML_STREAM_START_EVENT  +

A STREAM-START event.

+
YAML_STREAM_END_EVENT  +

A STREAM-END event.

+
YAML_DOCUMENT_START_EVENT  +

A DOCUMENT-START event.

+
YAML_DOCUMENT_END_EVENT  +

A DOCUMENT-END event.

+
YAML_ALIAS_EVENT  +

An ALIAS event.

+
YAML_SCALAR_EVENT  +

A SCALAR event.

+
YAML_SEQUENCE_START_EVENT  +

A SEQUENCE-START event.

+
YAML_SEQUENCE_END_EVENT  +

A SEQUENCE-END event.

+
YAML_MAPPING_START_EVENT  +

A MAPPING-START event.

+
YAML_MAPPING_END_EVENT  +

A MAPPING-END event.

+
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_stream_start_event_initialize (yaml_event_tevent,
yaml_encoding_t encoding 
)
+
+
+ +

Create the STREAM-START event.

+
Parameters:
+ + + +
[out]eventAn empty event object.
[in]encodingThe stream encoding.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
int yaml_stream_end_event_initialize (yaml_event_tevent)
+
+
+ +

Create the STREAM-END event.

+
Parameters:
+ + +
[out]eventAn empty event object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_start_event_initialize (yaml_event_tevent,
yaml_version_directive_tversion_directive,
yaml_tag_directive_ttag_directives_start,
yaml_tag_directive_ttag_directives_end,
int implicit 
)
+
+
+ +

Create the DOCUMENT-START event.

+

The implicit argument is considered as a stylistic parameter and may be ignored by the emitter.

+
Parameters:
+ + + + + + +
[out]eventAn empty event object.
[in]version_directiveThe YAML directive value or NULL.
[in]tag_directives_startThe beginning of the TAG directives list.
[in]tag_directives_endThe end of the TAG directives list.
[in]implicitIf the document start indicator is implicit.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_document_end_event_initialize (yaml_event_tevent,
int implicit 
)
+
+
+ +

Create the DOCUMENT-END event.

+

The implicit argument is considered as a stylistic parameter and may be ignored by the emitter.

+
Parameters:
+ + + +
[out]eventAn empty event object.
[in]implicitIf the document end indicator is implicit.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_alias_event_initialize (yaml_event_tevent,
yaml_char_tanchor 
)
+
+
+ +

Create an ALIAS event.

+
Parameters:
+ + + +
[out]eventAn empty event object.
[in]anchorThe anchor value.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_scalar_event_initialize (yaml_event_tevent,
yaml_char_tanchor,
yaml_char_ttag,
yaml_char_tvalue,
int length,
int plain_implicit,
int quoted_implicit,
yaml_scalar_style_t style 
)
+
+
+ +

Create a SCALAR event.

+

The style argument may be ignored by the emitter.

+

Either the tag attribute or one of the plain_implicit and quoted_implicit flags must be set.

+
Parameters:
+ + + + + + + + + +
[out]eventAn empty event object.
[in]anchorThe scalar anchor or NULL.
[in]tagThe scalar tag or NULL.
[in]valueThe scalar value.
[in]lengthThe length of the scalar value.
[in]plain_implicitIf the tag may be omitted for the plain style.
[in]quoted_implicitIf the tag may be omitted for any non-plain style.
[in]styleThe scalar style.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_sequence_start_event_initialize (yaml_event_tevent,
yaml_char_tanchor,
yaml_char_ttag,
int implicit,
yaml_sequence_style_t style 
)
+
+
+ +

Create a SEQUENCE-START event.

+

The style argument may be ignored by the emitter.

+

Either the tag attribute or the implicit flag must be set.

+
Parameters:
+ + + + + + +
[out]eventAn empty event object.
[in]anchorThe sequence anchor or NULL.
[in]tagThe sequence tag or NULL.
[in]implicitIf the tag may be omitted.
[in]styleThe sequence style.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
int yaml_sequence_end_event_initialize (yaml_event_tevent)
+
+
+ +

Create a SEQUENCE-END event.

+
Parameters:
+ + +
[out]eventAn empty event object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_mapping_start_event_initialize (yaml_event_tevent,
yaml_char_tanchor,
yaml_char_ttag,
int implicit,
yaml_mapping_style_t style 
)
+
+
+ +

Create a MAPPING-START event.

+

The style argument may be ignored by the emitter.

+

Either the tag attribute or the implicit flag must be set.

+
Parameters:
+ + + + + + +
[out]eventAn empty event object.
[in]anchorThe mapping anchor or NULL.
[in]tagThe mapping tag or NULL.
[in]implicitIf the tag may be omitted.
[in]styleThe mapping style.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
int yaml_mapping_end_event_initialize (yaml_event_tevent)
+
+
+ +

Create a MAPPING-END event.

+
Parameters:
+ + +
[out]eventAn empty event object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
void yaml_event_delete (yaml_event_tevent)
+
+
+ +

Free any memory allocated for an event object.

+
Parameters:
+ + +
[in,out]eventAn event object.
+
+
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__export.html b/libyaml/doc/html/group__export.html new file mode 100644 index 00000000..9f4a9871 --- /dev/null +++ b/libyaml/doc/html/group__export.html @@ -0,0 +1,91 @@ + + + + + +yaml: Export Definitions + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+ +
+
Export Definitions
+
+
+ + + + +

+Defines

#define YAML_DECLARE(type)   type
 The public API declaration.
+

Define Documentation

+ +
+
+ + + + + + + + +
#define YAML_DECLARE( type)   type
+
+
+ +

The public API declaration.

+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__nodes.html b/libyaml/doc/html/group__nodes.html new file mode 100644 index 00000000..b7294714 --- /dev/null +++ b/libyaml/doc/html/group__nodes.html @@ -0,0 +1,824 @@ + + + + + +yaml: Nodes + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_node_pair_s
 An element of a mapping node. More...
struct  yaml_node_s
 The node structure. More...
struct  yaml_document_s
 The document structure. More...

+Defines

#define YAML_NULL_TAG   "tag:yaml.org,2002:null"
 The tag !!null with the only possible value: null.
#define YAML_BOOL_TAG   "tag:yaml.org,2002:bool"
 The tag !!bool with the values: true and falce.
#define YAML_STR_TAG   "tag:yaml.org,2002:str"
 The tag !!str for string values.
#define YAML_INT_TAG   "tag:yaml.org,2002:int"
 The tag !!int for integer values.
#define YAML_FLOAT_TAG   "tag:yaml.org,2002:float"
 The tag !!float for float values.
#define YAML_TIMESTAMP_TAG   "tag:yaml.org,2002:timestamp"
 The tag !!timestamp for date and time values.
#define YAML_SEQ_TAG   "tag:yaml.org,2002:seq"
 The tag !!seq is used to denote sequences.
#define YAML_MAP_TAG   "tag:yaml.org,2002:map"
 The tag !!map is used to denote mapping.
#define YAML_DEFAULT_SCALAR_TAG   YAML_STR_TAG
 The default scalar tag is !!str.
#define YAML_DEFAULT_SEQUENCE_TAG   YAML_SEQ_TAG
 The default sequence tag is !!seq.
#define YAML_DEFAULT_MAPPING_TAG   YAML_MAP_TAG
 The default mapping tag is !!map.

+Typedefs

typedef enum yaml_node_type_e yaml_node_type_t
 Node types.
typedef struct yaml_node_s yaml_node_t
 The forward definition of a document node structure.
typedef int yaml_node_item_t
 An element of a sequence node.
typedef struct yaml_node_pair_s yaml_node_pair_t
 An element of a mapping node.
typedef struct yaml_document_s yaml_document_t
 The document structure.

+Enumerations

enum  yaml_node_type_e {
+  YAML_NO_NODE, +
+  YAML_SCALAR_NODE, +
+  YAML_SEQUENCE_NODE, +
+  YAML_MAPPING_NODE +
+ }
 Node types. More...

+Functions

int yaml_document_initialize (yaml_document_t *document, yaml_version_directive_t *version_directive, yaml_tag_directive_t *tag_directives_start, yaml_tag_directive_t *tag_directives_end, int start_implicit, int end_implicit)
 Create a YAML document.
void yaml_document_delete (yaml_document_t *document)
 Delete a YAML document and all its nodes.
yaml_node_tyaml_document_get_node (yaml_document_t *document, int index)
 Get a node of a YAML document.
yaml_node_tyaml_document_get_root_node (yaml_document_t *document)
 Get the root of a YAML document node.
int yaml_document_add_scalar (yaml_document_t *document, yaml_char_t *tag, yaml_char_t *value, int length, yaml_scalar_style_t style)
 Create a SCALAR node and attach it to the document.
int yaml_document_add_sequence (yaml_document_t *document, yaml_char_t *tag, yaml_sequence_style_t style)
 Create a SEQUENCE node and attach it to the document.
int yaml_document_add_mapping (yaml_document_t *document, yaml_char_t *tag, yaml_mapping_style_t style)
 Create a MAPPING node and attach it to the document.
int yaml_document_append_sequence_item (yaml_document_t *document, int sequence, int item)
 Add an item to a SEQUENCE node.
int yaml_document_append_mapping_pair (yaml_document_t *document, int mapping, int key, int value)
 Add a pair of a key and a value to a MAPPING node.
+

Define Documentation

+ +
+
+ + + + +
#define YAML_NULL_TAG   "tag:yaml.org,2002:null"
+
+
+ +

The tag !!null with the only possible value: null.

+ +
+
+ +
+
+ + + + +
#define YAML_BOOL_TAG   "tag:yaml.org,2002:bool"
+
+
+ +

The tag !!bool with the values: true and falce.

+ +
+
+ +
+
+ + + + +
#define YAML_STR_TAG   "tag:yaml.org,2002:str"
+
+
+ +

The tag !!str for string values.

+ +
+
+ +
+
+ + + + +
#define YAML_INT_TAG   "tag:yaml.org,2002:int"
+
+
+ +

The tag !!int for integer values.

+ +
+
+ +
+
+ + + + +
#define YAML_FLOAT_TAG   "tag:yaml.org,2002:float"
+
+
+ +

The tag !!float for float values.

+ +
+
+ +
+
+ + + + +
#define YAML_TIMESTAMP_TAG   "tag:yaml.org,2002:timestamp"
+
+
+ +

The tag !!timestamp for date and time values.

+ +
+
+ +
+
+ + + + +
#define YAML_SEQ_TAG   "tag:yaml.org,2002:seq"
+
+
+ +

The tag !!seq is used to denote sequences.

+ +
+
+ +
+
+ + + + +
#define YAML_MAP_TAG   "tag:yaml.org,2002:map"
+
+
+ +

The tag !!map is used to denote mapping.

+ +
+
+ +
+
+ + + + +
#define YAML_DEFAULT_SCALAR_TAG   YAML_STR_TAG
+
+
+ +

The default scalar tag is !!str.

+ +
+
+ +
+
+ + + + +
#define YAML_DEFAULT_SEQUENCE_TAG   YAML_SEQ_TAG
+
+
+ +

The default sequence tag is !!seq.

+ +
+
+ +
+
+ + + + +
#define YAML_DEFAULT_MAPPING_TAG   YAML_MAP_TAG
+
+
+ +

The default mapping tag is !!map.

+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef enum yaml_node_type_e yaml_node_type_t
+
+
+ +

Node types.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_node_s yaml_node_t
+
+
+ +

The forward definition of a document node structure.

+ +
+
+ +
+
+ + + + +
typedef int yaml_node_item_t
+
+
+ +

An element of a sequence node.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_node_pair_s yaml_node_pair_t
+
+
+ +

An element of a mapping node.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_document_s yaml_document_t
+
+
+ +

The document structure.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_node_type_e
+
+
+ +

Node types.

+
Enumerator:
+ + + + +
YAML_NO_NODE  +

An empty node.

+
YAML_SCALAR_NODE  +

A scalar node.

+
YAML_SEQUENCE_NODE  +

A sequence node.

+
YAML_MAPPING_NODE  +

A mapping node.

+
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_initialize (yaml_document_tdocument,
yaml_version_directive_tversion_directive,
yaml_tag_directive_ttag_directives_start,
yaml_tag_directive_ttag_directives_end,
int start_implicit,
int end_implicit 
)
+
+
+ +

Create a YAML document.

+
Parameters:
+ + + + + + + +
[out]documentAn empty document object.
[in]version_directiveThe YAML directive value or NULL.
[in]tag_directives_startThe beginning of the TAG directives list.
[in]tag_directives_endThe end of the TAG directives list.
[in]start_implicitIf the document start indicator is implicit.
[in]end_implicitIf the document end indicator is implicit.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
void yaml_document_delete (yaml_document_tdocument)
+
+
+ +

Delete a YAML document and all its nodes.

+
Parameters:
+ + +
[in,out]documentA document object.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
yaml_node_t* yaml_document_get_node (yaml_document_tdocument,
int index 
)
+
+
+ +

Get a node of a YAML document.

+

The pointer returned by this function is valid until any of the functions modifying the documents are called.

+
Parameters:
+ + + +
[in]documentA document object.
[in]indexThe node id.
+
+
+
Returns:
the node objct or NULL if node_id is out of range.
+ +
+
+ +
+
+ + + + + + + + +
yaml_node_t* yaml_document_get_root_node (yaml_document_tdocument)
+
+
+ +

Get the root of a YAML document node.

+

The root object is the first object added to the document.

+

The pointer returned by this function is valid until any of the functions modifying the documents are called.

+

An empty document produced by the parser signifies the end of a YAML stream.

+
Parameters:
+ + +
[in]documentA document object.
+
+
+
Returns:
the node object or NULL if the document is empty.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_add_scalar (yaml_document_tdocument,
yaml_char_ttag,
yaml_char_tvalue,
int length,
yaml_scalar_style_t style 
)
+
+
+ +

Create a SCALAR node and attach it to the document.

+

The style argument may be ignored by the emitter.

+
Parameters:
+ + + + + + +
[in,out]documentA document object.
[in]tagThe scalar tag.
[in]valueThe scalar value.
[in]lengthThe length of the scalar value.
[in]styleThe scalar style.
+
+
+
Returns:
the node id or 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_add_sequence (yaml_document_tdocument,
yaml_char_ttag,
yaml_sequence_style_t style 
)
+
+
+ +

Create a SEQUENCE node and attach it to the document.

+

The style argument may be ignored by the emitter.

+
Parameters:
+ + + + +
[in,out]documentA document object.
[in]tagThe sequence tag.
[in]styleThe sequence style.
+
+
+
Returns:
the node id or 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_add_mapping (yaml_document_tdocument,
yaml_char_ttag,
yaml_mapping_style_t style 
)
+
+
+ +

Create a MAPPING node and attach it to the document.

+

The style argument may be ignored by the emitter.

+
Parameters:
+ + + + +
[in,out]documentA document object.
[in]tagThe sequence tag.
[in]styleThe sequence style.
+
+
+
Returns:
the node id or 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_append_sequence_item (yaml_document_tdocument,
int sequence,
int item 
)
+
+
+ +

Add an item to a SEQUENCE node.

+
Parameters:
+ + + + +
[in,out]documentA document object.
[in]sequenceThe sequence node id.
[in]itemThe item node id.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int yaml_document_append_mapping_pair (yaml_document_tdocument,
int mapping,
int key,
int value 
)
+
+
+ +

Add a pair of a key and a value to a MAPPING node.

+
Parameters:
+ + + + + +
[in,out]documentA document object.
[in]mappingThe mapping node id.
[in]keyThe key node id.
[in]valueThe value node id.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__parser.html b/libyaml/doc/html/group__parser.html new file mode 100644 index 00000000..5b1d9dec --- /dev/null +++ b/libyaml/doc/html/group__parser.html @@ -0,0 +1,635 @@ + + + + + +yaml: Parser Definitions + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+ +
+
Parser Definitions
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_simple_key_s
 This structure holds information about a potential simple key. More...
struct  yaml_alias_data_s
 This structure holds aliases data. More...
struct  yaml_parser_s
 The parser structure. More...

+Typedefs

typedef int yaml_read_handler_t (void *data, unsigned char *buffer, size_t size, size_t *size_read)
 The prototype of a read handler.
+typedef struct yaml_simple_key_s yaml_simple_key_t
 This structure holds information about a potential simple key.
+typedef enum yaml_parser_state_e yaml_parser_state_t
 The states of the parser.
+typedef struct yaml_alias_data_s yaml_alias_data_t
 This structure holds aliases data.
typedef struct yaml_parser_s yaml_parser_t
 The parser structure.

+Enumerations

enum  yaml_parser_state_e {
+  YAML_PARSE_STREAM_START_STATE, +
+  YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, +
+  YAML_PARSE_DOCUMENT_START_STATE, +
+  YAML_PARSE_DOCUMENT_CONTENT_STATE, +
+  YAML_PARSE_DOCUMENT_END_STATE, +
+  YAML_PARSE_BLOCK_NODE_STATE, +
+  YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, +
+  YAML_PARSE_FLOW_NODE_STATE, +
+  YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, +
+  YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, +
+  YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, +
+  YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, +
+  YAML_PARSE_BLOCK_MAPPING_KEY_STATE, +
+  YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, +
+  YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, +
+  YAML_PARSE_FLOW_MAPPING_KEY_STATE, +
+  YAML_PARSE_FLOW_MAPPING_VALUE_STATE, +
+  YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, +
+  YAML_PARSE_END_STATE +
+ }
 The states of the parser. More...

+Functions

int yaml_parser_initialize (yaml_parser_t *parser)
 Initialize a parser.
void yaml_parser_delete (yaml_parser_t *parser)
 Destroy a parser.
void yaml_parser_set_input_string (yaml_parser_t *parser, const unsigned char *input, size_t size)
 Set a string input.
void yaml_parser_set_input_file (yaml_parser_t *parser, FILE *file)
 Set a file input.
void yaml_parser_set_input (yaml_parser_t *parser, yaml_read_handler_t *handler, void *data)
 Set a generic input handler.
void yaml_parser_set_encoding (yaml_parser_t *parser, yaml_encoding_t encoding)
 Set the source encoding.
int yaml_parser_scan (yaml_parser_t *parser, yaml_token_t *token)
 Scan the input stream and produce the next token.
int yaml_parser_parse (yaml_parser_t *parser, yaml_event_t *event)
 Parse the input stream and produce the next parsing event.
int yaml_parser_load (yaml_parser_t *parser, yaml_document_t *document)
 Parse the input stream and produce the next YAML document.
+

Typedef Documentation

+ +
+
+ + + + +
typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size, size_t *size_read)
+
+
+ +

The prototype of a read handler.

+

The read handler is called when the parser needs to read more bytes from the source. The handler should write not more than size bytes to the buffer. The number of written bytes should be set to the length variable.

+
Parameters:
+ + + + + +
[in,out]dataA pointer to an application data specified by yaml_parser_set_input().
[out]bufferThe buffer to write the data from the source.
[in]sizeThe size of the buffer.
[out]size_readThe actual number of bytes read from the source.
+
+
+
Returns:
On success, the handler should return 1. If the handler failed, the returned value should be 0. On EOF, the handler should set the size_read to 0 and return 1.
+ +
+
+ +
+
+ + + + +
typedef struct yaml_parser_s yaml_parser_t
+
+
+ +

The parser structure.

+

All members are internal. Manage the structure using the yaml_parser_ family of functions.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_parser_state_e
+
+
+ +

The states of the parser.

+
Enumerator:
+ + + + + + + + + + + + + + + + + + + + + + + + +
YAML_PARSE_STREAM_START_STATE  +

Expect STREAM-START.

+
YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE  +

Expect the beginning of an implicit document.

+
YAML_PARSE_DOCUMENT_START_STATE  +

Expect DOCUMENT-START.

+
YAML_PARSE_DOCUMENT_CONTENT_STATE  +

Expect the content of a document.

+
YAML_PARSE_DOCUMENT_END_STATE  +

Expect DOCUMENT-END.

+
YAML_PARSE_BLOCK_NODE_STATE  +

Expect a block node.

+
YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE  +

Expect a block node or indentless sequence.

+
YAML_PARSE_FLOW_NODE_STATE  +

Expect a flow node.

+
YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE  +

Expect the first entry of a block sequence.

+
YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE  +

Expect an entry of a block sequence.

+
YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE  +

Expect an entry of an indentless sequence.

+
YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE  +

Expect the first key of a block mapping.

+
YAML_PARSE_BLOCK_MAPPING_KEY_STATE  +

Expect a block mapping key.

+
YAML_PARSE_BLOCK_MAPPING_VALUE_STATE  +

Expect a block mapping value.

+
YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE  +

Expect the first entry of a flow sequence.

+
YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE  +

Expect an entry of a flow sequence.

+
YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE  +

Expect a key of an ordered mapping.

+
YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE  +

Expect a value of an ordered mapping.

+
YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE  +

Expect the and of an ordered mapping entry.

+
YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE  +

Expect the first key of a flow mapping.

+
YAML_PARSE_FLOW_MAPPING_KEY_STATE  +

Expect a key of a flow mapping.

+
YAML_PARSE_FLOW_MAPPING_VALUE_STATE  +

Expect a value of a flow mapping.

+
YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE  +

Expect an empty value of a flow mapping.

+
YAML_PARSE_END_STATE  +

Expect nothing.

+
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
int yaml_parser_initialize (yaml_parser_tparser)
+
+
+ +

Initialize a parser.

+

This function creates a new parser object. An application is responsible for destroying the object using the yaml_parser_delete() function.

+
Parameters:
+ + +
[out]parserAn empty parser object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + +
void yaml_parser_delete (yaml_parser_tparser)
+
+
+ +

Destroy a parser.

+
Parameters:
+ + +
[in,out]parserA parser object.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void yaml_parser_set_input_string (yaml_parser_tparser,
const unsigned char * input,
size_t size 
)
+
+
+ +

Set a string input.

+

Note that the input pointer must be valid while the parser object exists. The application is responsible for destroing input after destroying the parser.

+
Parameters:
+ + + + +
[in,out]parserA parser object.
[in]inputA source data.
[in]sizeThe length of the source data in bytes.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_parser_set_input_file (yaml_parser_tparser,
FILE * file 
)
+
+
+ +

Set a file input.

+

file should be a file object open for reading. The application is responsible for closing the file.

+
Parameters:
+ + + +
[in,out]parserA parser object.
[in]fileAn open file.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void yaml_parser_set_input (yaml_parser_tparser,
yaml_read_handler_thandler,
void * data 
)
+
+
+ +

Set a generic input handler.

+
Parameters:
+ + + + +
[in,out]parserA parser object.
[in]handlerA read handler.
[in]dataAny application data for passing to the read handler.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void yaml_parser_set_encoding (yaml_parser_tparser,
yaml_encoding_t encoding 
)
+
+
+ +

Set the source encoding.

+
Parameters:
+ + + +
[in,out]parserA parser object.
[in]encodingThe source encoding.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_parser_scan (yaml_parser_tparser,
yaml_token_ttoken 
)
+
+
+ +

Scan the input stream and produce the next token.

+

Call the function subsequently to produce a sequence of tokens corresponding to the input stream. The initial token has the type YAML_STREAM_START_TOKEN while the ending token has the type YAML_STREAM_END_TOKEN.

+

An application is responsible for freeing any buffers associated with the produced token object using the yaml_token_delete function.

+

An application must not alternate the calls of yaml_parser_scan() with the calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break the parser.

+
Parameters:
+ + + +
[in,out]parserA parser object.
[out]tokenAn empty token object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_parser_parse (yaml_parser_tparser,
yaml_event_tevent 
)
+
+
+ +

Parse the input stream and produce the next parsing event.

+

Call the function subsequently to produce a sequence of events corresponding to the input stream. The initial event has the type YAML_STREAM_START_EVENT while the ending event has the type YAML_STREAM_END_EVENT.

+

An application is responsible for freeing any buffers associated with the produced event object using the yaml_event_delete() function.

+

An application must not alternate the calls of yaml_parser_parse() with the calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the parser.

+
Parameters:
+ + + +
[in,out]parserA parser object.
[out]eventAn empty event object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int yaml_parser_load (yaml_parser_tparser,
yaml_document_tdocument 
)
+
+
+ +

Parse the input stream and produce the next YAML document.

+

Call this function subsequently to produce a sequence of documents constituting the input stream.

+

If the produced document has no root node, it means that the document end has been reached.

+

An application is responsible for freeing any data associated with the produced document object using the yaml_document_delete() function.

+

An application must not alternate the calls of yaml_parser_load() with the calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break the parser.

+
Parameters:
+ + + +
[in,out]parserA parser object.
[out]documentAn empty document object.
+
+
+
Returns:
1 if the function succeeded, 0 on error.
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__styles.html b/libyaml/doc/html/group__styles.html new file mode 100644 index 00000000..c3636d66 --- /dev/null +++ b/libyaml/doc/html/group__styles.html @@ -0,0 +1,251 @@ + + + + + +yaml: Node Styles + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+ +
+
Node Styles
+
+
+ + + + + + + + + + + + + + + +

+Typedefs

typedef enum yaml_scalar_style_e yaml_scalar_style_t
 Scalar styles.
typedef enum yaml_sequence_style_e yaml_sequence_style_t
 Sequence styles.
typedef enum yaml_mapping_style_e yaml_mapping_style_t
 Mapping styles.

+Enumerations

enum  yaml_scalar_style_e {
+  YAML_ANY_SCALAR_STYLE, +
+  YAML_PLAIN_SCALAR_STYLE, +
+  YAML_SINGLE_QUOTED_SCALAR_STYLE, +
+  YAML_DOUBLE_QUOTED_SCALAR_STYLE, +
+  YAML_LITERAL_SCALAR_STYLE, +
+  YAML_FOLDED_SCALAR_STYLE +
+ }
 Scalar styles. More...
enum  yaml_sequence_style_e {
+  YAML_ANY_SEQUENCE_STYLE, +
+  YAML_BLOCK_SEQUENCE_STYLE, +
+  YAML_FLOW_SEQUENCE_STYLE +
+ }
 Sequence styles. More...
enum  yaml_mapping_style_e {
+  YAML_ANY_MAPPING_STYLE, +
+  YAML_BLOCK_MAPPING_STYLE, +
+  YAML_FLOW_MAPPING_STYLE +
+ }
 Mapping styles. More...
+

Typedef Documentation

+ +
+
+ + + + +
typedef enum yaml_scalar_style_e yaml_scalar_style_t
+
+
+ +

Scalar styles.

+ +
+
+ +
+ +
+ +

Sequence styles.

+ +
+
+ +
+
+ + + + +
typedef enum yaml_mapping_style_e yaml_mapping_style_t
+
+
+ +

Mapping styles.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_scalar_style_e
+
+
+ +

Scalar styles.

+
Enumerator:
+ + + + + + +
YAML_ANY_SCALAR_STYLE  +

Let the emitter choose the style.

+
YAML_PLAIN_SCALAR_STYLE  +

The plain scalar style.

+
YAML_SINGLE_QUOTED_SCALAR_STYLE  +

The single-quoted scalar style.

+
YAML_DOUBLE_QUOTED_SCALAR_STYLE  +

The double-quoted scalar style.

+
YAML_LITERAL_SCALAR_STYLE  +

The literal scalar style.

+
YAML_FOLDED_SCALAR_STYLE  +

The folded scalar style.

+
+
+
+ +
+
+ +
+
+ + + + +
enum yaml_sequence_style_e
+
+
+ +

Sequence styles.

+
Enumerator:
+ + + +
YAML_ANY_SEQUENCE_STYLE  +

Let the emitter choose the style.

+
YAML_BLOCK_SEQUENCE_STYLE  +

The block sequence style.

+
YAML_FLOW_SEQUENCE_STYLE  +

The flow sequence style.

+
+
+
+ +
+
+ +
+
+ + + + +
enum yaml_mapping_style_e
+
+
+ +

Mapping styles.

+
Enumerator:
+ + + +
YAML_ANY_MAPPING_STYLE  +

Let the emitter choose the style.

+
YAML_BLOCK_MAPPING_STYLE  +

The block mapping style.

+
YAML_FLOW_MAPPING_STYLE  +

The flow mapping style.

+
+
+
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__tokens.html b/libyaml/doc/html/group__tokens.html new file mode 100644 index 00000000..dcd5bc51 --- /dev/null +++ b/libyaml/doc/html/group__tokens.html @@ -0,0 +1,276 @@ + + + + + +yaml: Tokens + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+ +
+ + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_token_s
 The token structure. More...

+Typedefs

typedef enum yaml_token_type_e yaml_token_type_t
 Token types.
typedef struct yaml_token_s yaml_token_t
 The token structure.

+Enumerations

enum  yaml_token_type_e {
+  YAML_NO_TOKEN, +
+  YAML_STREAM_START_TOKEN, +
+  YAML_STREAM_END_TOKEN, +
+  YAML_VERSION_DIRECTIVE_TOKEN, +
+  YAML_TAG_DIRECTIVE_TOKEN, +
+  YAML_DOCUMENT_START_TOKEN, +
+  YAML_DOCUMENT_END_TOKEN, +
+  YAML_BLOCK_SEQUENCE_START_TOKEN, +
+  YAML_BLOCK_MAPPING_START_TOKEN, +
+  YAML_BLOCK_END_TOKEN, +
+  YAML_FLOW_SEQUENCE_START_TOKEN, +
+  YAML_FLOW_SEQUENCE_END_TOKEN, +
+  YAML_FLOW_MAPPING_START_TOKEN, +
+  YAML_FLOW_MAPPING_END_TOKEN, +
+  YAML_BLOCK_ENTRY_TOKEN, +
+  YAML_FLOW_ENTRY_TOKEN, +
+  YAML_KEY_TOKEN, +
+  YAML_VALUE_TOKEN, +
+  YAML_ALIAS_TOKEN, +
+  YAML_ANCHOR_TOKEN, +
+  YAML_TAG_TOKEN, +
+  YAML_SCALAR_TOKEN +
+ }
 Token types. More...

+Functions

void yaml_token_delete (yaml_token_t *token)
 Free any memory allocated for a token object.
+

Typedef Documentation

+ +
+
+ + + + +
typedef enum yaml_token_type_e yaml_token_type_t
+
+
+ +

Token types.

+ +
+
+ +
+
+ + + + +
typedef struct yaml_token_s yaml_token_t
+
+
+ +

The token structure.

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum yaml_token_type_e
+
+
+ +

Token types.

+
Enumerator:
+ + + + + + + + + + + + + + + + + + + + + + +
YAML_NO_TOKEN  +

An empty token.

+
YAML_STREAM_START_TOKEN  +

A STREAM-START token.

+
YAML_STREAM_END_TOKEN  +

A STREAM-END token.

+
YAML_VERSION_DIRECTIVE_TOKEN  +

A VERSION-DIRECTIVE token.

+
YAML_TAG_DIRECTIVE_TOKEN  +

A TAG-DIRECTIVE token.

+
YAML_DOCUMENT_START_TOKEN  +

A DOCUMENT-START token.

+
YAML_DOCUMENT_END_TOKEN  +

A DOCUMENT-END token.

+
YAML_BLOCK_SEQUENCE_START_TOKEN  +

A BLOCK-SEQUENCE-START token.

+
YAML_BLOCK_MAPPING_START_TOKEN  +

A BLOCK-SEQUENCE-END token.

+
YAML_BLOCK_END_TOKEN  +

A BLOCK-END token.

+
YAML_FLOW_SEQUENCE_START_TOKEN  +

A FLOW-SEQUENCE-START token.

+
YAML_FLOW_SEQUENCE_END_TOKEN  +

A FLOW-SEQUENCE-END token.

+
YAML_FLOW_MAPPING_START_TOKEN  +

A FLOW-MAPPING-START token.

+
YAML_FLOW_MAPPING_END_TOKEN  +

A FLOW-MAPPING-END token.

+
YAML_BLOCK_ENTRY_TOKEN  +

A BLOCK-ENTRY token.

+
YAML_FLOW_ENTRY_TOKEN  +

A FLOW-ENTRY token.

+
YAML_KEY_TOKEN  +

A KEY token.

+
YAML_VALUE_TOKEN  +

A VALUE token.

+
YAML_ALIAS_TOKEN  +

An ALIAS token.

+
YAML_ANCHOR_TOKEN  +

An ANCHOR token.

+
YAML_TAG_TOKEN  +

A TAG token.

+
YAML_SCALAR_TOKEN  +

A SCALAR token.

+
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void yaml_token_delete (yaml_token_ttoken)
+
+
+ +

Free any memory allocated for a token object.

+
Parameters:
+ + +
[in,out]tokenA token object.
+
+
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/group__version.html b/libyaml/doc/html/group__version.html new file mode 100644 index 00000000..98b6fc01 --- /dev/null +++ b/libyaml/doc/html/group__version.html @@ -0,0 +1,137 @@ + + + + + +yaml: Version Information + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+ +
+
Version Information
+
+
+ + + + + + +

+Functions

const char * yaml_get_version_string (void)
 Get the library version as a string.
void yaml_get_version (int *major, int *minor, int *patch)
 Get the library version numbers.
+

Function Documentation

+ +
+
+ + + + + + + + +
const char* yaml_get_version_string (void )
+
+
+ +

Get the library version as a string.

+
Returns:
The function returns the pointer to a static string of the form "X.Y.Z", where X is the major version number, Y is a minor version number, and Z is the patch version number.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void yaml_get_version (int * major,
int * minor,
int * patch 
)
+
+
+ +

Get the library version numbers.

+
Parameters:
+ + + + +
[out]majorMajor version number.
[out]minorMinor version number.
[out]patchPatch version number.
+
+
+ +
+
+
+ + + + + + diff --git a/libyaml/doc/html/index.html b/libyaml/doc/html/index.html new file mode 100644 index 00000000..36e5f0f2 --- /dev/null +++ b/libyaml/doc/html/index.html @@ -0,0 +1,63 @@ + + + + + +yaml: Main Page + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+
+
yaml Documentation
+
+
+
+ + + + + + diff --git a/libyaml/doc/html/modules.html b/libyaml/doc/html/modules.html new file mode 100644 index 00000000..039e1656 --- /dev/null +++ b/libyaml/doc/html/modules.html @@ -0,0 +1,74 @@ + + + + + +yaml: Modules + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + +
+
+
+
Modules
+
+ + + + + + + diff --git a/libyaml/doc/html/nav_f.png b/libyaml/doc/html/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..1b07a16207e67c95fe2ee17e7016e6d08ac7ac99 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQfZzpjv*C{Z|{2YIT`Y>1X`Eg z-tTbne1`SITM8Q!Pb(<)UFZ(m>wMzvKZQqKM~~GcZ=A7j<~E6K62>ozFS=cD3)mf8 z9WX0+R&m(l9KUsLdTx4?9~({T__KA%`}olPJ^N;y|F^pHgs_K%!rj~{8>RwnWbkzL Kb6Mw<&;$VTdq1fF literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/nav_h.png b/libyaml/doc/html/nav_h.png new file mode 100644 index 0000000000000000000000000000000000000000..01f5fa6a596e36bd12c2d6ceff1b0169fda7e699 GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^j6lr8!2~3AUOE6t1`SUa$B+ufw|6&kG8phMJMJ~w va4>Y+bZ&9QY?(VEUPY_cGd9nQ`um^ZSUyYpAAuKhL7F^W{an^LB{Ts5DmojT literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/open.png b/libyaml/doc/html/open.png new file mode 100644 index 0000000000000000000000000000000000000000..7b35d2c2c389743089632fe24c3104f2173d97af GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{Vww^AIAr*{o=Nbw!DDW^(zOibV zl!F8B0?t?i!vld4k#$~0_AX3zElaokn + + + + +yaml: yaml_alias_data_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_alias_data_s Struct Reference
+
+
+ +

This structure holds aliases data. + More...

+ +

#include <yaml.h>

+ + + + + + + + +

+Data Fields

yaml_char_tanchor
 The anchor.
int index
 The node id.
yaml_mark_t mark
 The anchor mark.
+

Detailed Description

+

This structure holds aliases data.

+

Field Documentation

+ +
+ +
+ +

The anchor.

+ +
+
+ +
+
+ + + + +
int yaml_alias_data_s::index
+
+
+ +

The node id.

+ +
+
+ +
+ +
+ +

The anchor mark.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__document__s.html b/libyaml/doc/html/structyaml__document__s.html new file mode 100644 index 00000000..a9b66d2d --- /dev/null +++ b/libyaml/doc/html/structyaml__document__s.html @@ -0,0 +1,264 @@ + + + + + +yaml: yaml_document_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_document_s Struct Reference
+
+
+ +

The document structure. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

struct {
   yaml_node_t *   start
 The beginning of the stack.
   yaml_node_t *   end
 The end of the stack.
   yaml_node_t *   top
 The top of the stack.
nodes
 The document nodes.
yaml_version_directive_tversion_directive
 The version directive.
struct {
   yaml_tag_directive_t *   start
 The beginning of the tag directives list.
   yaml_tag_directive_t *   end
 The end of the tag directives list.
tag_directives
 The list of tag directives.
+int start_implicit
 Is the document start indicator implicit?
+int end_implicit
 Is the document end indicator implicit?
yaml_mark_t start_mark
 The beginning of the document.
yaml_mark_t end_mark
 The end of the document.
+

Detailed Description

+

The document structure.

+

Field Documentation

+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_document_s::nodes
+
+
+ +

The document nodes.

+ +
+
+ +
+ +
+ +

The version directive.

+ +
+
+ +
+ +
+ +

The beginning of the tag directives list.

+ +
+
+ +
+ +
+ +

The end of the tag directives list.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_document_s::tag_directives
+
+
+ +

The list of tag directives.

+ +
+
+ +
+ +
+ +

The beginning of the document.

+ +
+
+ +
+ +
+ +

The end of the document.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__emitter__s.html b/libyaml/doc/html/structyaml__emitter__s.html new file mode 100644 index 00000000..ca5b0a5a --- /dev/null +++ b/libyaml/doc/html/structyaml__emitter__s.html @@ -0,0 +1,1321 @@ + + + + + +yaml: yaml_emitter_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+
+
yaml_emitter_s Struct Reference
+
+
+ +

The emitter structure. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

unsigned char * buffer
 The buffer pointer.
size_t size
 The buffer size.
size_t * size_written
 The number of written bytes.
struct {
   unsigned char *   buffer
 The buffer pointer.
   size_t   size
 The buffer size.
   size_t *   size_written
 The number of written bytes.
string
 String output data.
FILE * file
 File output data.
yaml_char_tstart
 The beginning of the buffer.
yaml_char_tend
 The end of the buffer.
yaml_char_tpointer
 The current position of the buffer.
yaml_char_tlast
 The last filled position of the buffer.
unsigned char * start
 The beginning of the buffer.
unsigned char * end
 The end of the buffer.
unsigned char * pointer
 The current position of the buffer.
unsigned char * last
 The last filled position of the buffer.
yaml_emitter_state_tstart
 The beginning of the stack.
yaml_emitter_state_tend
 The end of the stack.
yaml_emitter_state_ttop
 The top of the stack.
yaml_event_tstart
 The beginning of the event queue.
yaml_event_tend
 The end of the event queue.
yaml_event_thead
 The head of the event queue.
yaml_event_ttail
 The tail of the event queue.
int * start
 The beginning of the stack.
int * end
 The end of the stack.
int * top
 The top of the stack.
yaml_tag_directive_tstart
 The beginning of the list.
yaml_tag_directive_tend
 The end of the list.
yaml_tag_directive_ttop
 The top of the list.
yaml_char_tanchor
 The anchor value.
size_t anchor_length
 The anchor length.
+int alias
 Is it an alias?
yaml_char_thandle
 The tag handle.
size_t handle_length
 The tag handle length.
yaml_char_tsuffix
 The tag suffix.
size_t suffix_length
 The tag suffix length.
yaml_char_tvalue
 The scalar value.
size_t length
 The scalar length.
+int multiline
 Does the scalar contain line breaks?
+int flow_plain_allowed
 Can the scalar be expessed in the flow plain style?
+int block_plain_allowed
 Can the scalar be expressed in the block plain style?
+int single_quoted_allowed
 Can the scalar be expressed in the single quoted style?
+int block_allowed
 Can the scalar be expressed in the literal or folded styles?
yaml_scalar_style_t style
 The output style.
int references
 The number of references.
int anchor
 The anchor id.
+int serialized
 If the node has been emitted?
Error handling
yaml_error_type_t error
 Error type.
const char * problem
 Error description.
Writer stuff
yaml_write_handler_twrite_handler
 Write handler.
void * write_handler_data
 A pointer for passing to the white handler.
union {
   struct {
      unsigned char *   buffer
 The buffer pointer.
      size_t   size
 The buffer size.
      size_t *   size_written
 The number of written bytes.
   }   string
 String output data.
   FILE *   file
 File output data.
output
 Standard (string or file) output data.
struct {
   yaml_char_t *   start
 The beginning of the buffer.
   yaml_char_t *   end
 The end of the buffer.
   yaml_char_t *   pointer
 The current position of the buffer.
   yaml_char_t *   last
 The last filled position of the buffer.
buffer
 The working buffer.
struct {
   unsigned char *   start
 The beginning of the buffer.
   unsigned char *   end
 The end of the buffer.
   unsigned char *   pointer
 The current position of the buffer.
   unsigned char *   last
 The last filled position of the buffer.
raw_buffer
 The raw buffer.
yaml_encoding_t encoding
 The stream encoding.
Emitter stuff
+int canonical
 If the output is in the canonical style?
int best_indent
 The number of indentation spaces.
int best_width
 The preferred width of the output lines.
+int unicode
 Allow unescaped non-ASCII characters?
yaml_break_t line_break
 The preferred line break.
struct {
   yaml_emitter_state_t *   start
 The beginning of the stack.
   yaml_emitter_state_t *   end
 The end of the stack.
   yaml_emitter_state_t *   top
 The top of the stack.
states
 The stack of states.
yaml_emitter_state_t state
 The current emitter state.
struct {
   yaml_event_t *   start
 The beginning of the event queue.
   yaml_event_t *   end
 The end of the event queue.
   yaml_event_t *   head
 The head of the event queue.
   yaml_event_t *   tail
 The tail of the event queue.
events
 The event queue.
struct {
   int *   start
 The beginning of the stack.
   int *   end
 The end of the stack.
   int *   top
 The top of the stack.
indents
 The stack of indentation levels.
struct {
   yaml_tag_directive_t *   start
 The beginning of the list.
   yaml_tag_directive_t *   end
 The end of the list.
   yaml_tag_directive_t *   top
 The top of the list.
tag_directives
 The list of tag directives.
int indent
 The current indentation level.
int flow_level
 The current flow level.
+int root_context
 Is it the document root context?
+int sequence_context
 Is it a sequence context?
+int mapping_context
 Is it a mapping context?
+int simple_key_context
 Is it a simple mapping key context?
int line
 The current line.
int column
 The current column.
+int whitespace
 If the last character was a whitespace?
+int indention
 If the last character was an indentation character (' ', '-', '?', ':')?
+int open_ended
 If an explicit document end is required?
struct {
   yaml_char_t *   anchor
 The anchor value.
   size_t   anchor_length
 The anchor length.
   int   alias
 Is it an alias?
anchor_data
 Anchor analysis.
struct {
   yaml_char_t *   handle
 The tag handle.
   size_t   handle_length
 The tag handle length.
   yaml_char_t *   suffix
 The tag suffix.
   size_t   suffix_length
 The tag suffix length.
tag_data
 Tag analysis.
struct {
   yaml_char_t *   value
 The scalar value.
   size_t   length
 The scalar length.
   int   multiline
 Does the scalar contain line breaks?
   int   flow_plain_allowed
 Can the scalar be expessed in the flow plain style?
   int   block_plain_allowed
 Can the scalar be expressed in the block plain style?
   int   single_quoted_allowed
 Can the scalar be expressed in the single quoted style?
   int   block_allowed
 Can the scalar be expressed in the literal or folded styles?
   yaml_scalar_style_t   style
 The output style.
scalar_data
 Scalar analysis.
Dumper stuff
+int opened
 If the stream was already opened?
+int closed
 If the stream was already closed?
struct {
   int   references
 The number of references.
   int   anchor
 The anchor id.
   int   serialized
 If the node has been emitted?
anchors
 The information associated with the document nodes.
int last_anchor_id
 The last assigned anchor id.
yaml_document_tdocument
 The currently emitted document.
+

Detailed Description

+

The emitter structure.

+

All members are internal. Manage the structure using the yaml_emitter_ family of functions.

+

Field Documentation

+ +
+ +
+ +

Error type.

+ +
+
+ +
+
+ + + + +
const char* yaml_emitter_s::problem
+
+
+ +

Error description.

+ +
+
+ +
+ +
+ +

Write handler.

+ +
+
+ +
+ +
+ +

A pointer for passing to the white handler.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_emitter_s::buffer
+
+
+ +

The buffer pointer.

+ +
+
+ +
+
+ + + + +
size_t yaml_emitter_s::size
+
+
+ +

The buffer size.

+ +
+
+ +
+
+ + + + +
size_t* yaml_emitter_s::size_written
+
+
+ +

The number of written bytes.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::string
+
+
+ +

String output data.

+ +
+
+ +
+
+ + + + +
FILE* yaml_emitter_s::file
+
+
+ +

File output data.

+ +
+
+ +
+
+ + + + +
union { ... } yaml_emitter_s::output
+
+
+ +

Standard (string or file) output data.

+ +
+
+ +
+ +
+ +

The beginning of the buffer.

+ +
+
+ +
+ +
+ +

The end of the buffer.

+ +
+
+ +
+ +
+ +

The current position of the buffer.

+ +
+
+ +
+ +
+ +

The last filled position of the buffer.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::buffer
+
+
+ +

The working buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_emitter_s::start
+
+
+ +

The beginning of the buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_emitter_s::end
+
+
+ +

The end of the buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_emitter_s::pointer
+
+
+ +

The current position of the buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_emitter_s::last
+
+
+ +

The last filled position of the buffer.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::raw_buffer
+
+
+ +

The raw buffer.

+ +
+
+ +
+ +
+ +

The stream encoding.

+ +
+
+ +
+ +
+ +

The number of indentation spaces.

+ +
+
+ +
+ +
+ +

The preferred width of the output lines.

+ +
+
+ +
+ +
+ +

The preferred line break.

+ +
+
+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::states
+
+
+ +

The stack of states.

+ +
+
+ +
+ +
+ +

The current emitter state.

+ +
+
+ +
+ +
+ +

The beginning of the event queue.

+ +
+
+ +
+ +
+ +

The end of the event queue.

+ +
+
+ +
+ +
+ +

The head of the event queue.

+ +
+
+ +
+ +
+ +

The tail of the event queue.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::events
+
+
+ +

The event queue.

+ +
+
+ +
+
+ + + + +
int* yaml_emitter_s::start
+
+
+ +

The beginning of the stack.

+ +
+
+ +
+
+ + + + +
int* yaml_emitter_s::end
+
+
+ +

The end of the stack.

+ +
+
+ +
+
+ + + + +
int* yaml_emitter_s::top
+
+
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::indents
+
+
+ +

The stack of indentation levels.

+ +
+
+ +
+ +
+ +

The beginning of the list.

+ +
+
+ +
+ +
+ +

The end of the list.

+ +
+
+ +
+ +
+ +

The top of the list.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::tag_directives
+
+
+ +

The list of tag directives.

+ +
+
+ +
+
+ + + + +
int yaml_emitter_s::indent
+
+
+ +

The current indentation level.

+ +
+
+ +
+ +
+ +

The current flow level.

+ +
+
+ +
+
+ + + + +
int yaml_emitter_s::line
+
+
+ +

The current line.

+ +
+
+ +
+
+ + + + +
int yaml_emitter_s::column
+
+
+ +

The current column.

+ +
+
+ +
+ +
+ +

The anchor value.

+ +
+
+ +
+
+ + + + +
size_t yaml_emitter_s::anchor_length
+
+
+ +

The anchor length.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::anchor_data
+
+
+ +

Anchor analysis.

+ +
+
+ +
+ +
+ +

The tag handle.

+ +
+
+ +
+
+ + + + +
size_t yaml_emitter_s::handle_length
+
+
+ +

The tag handle length.

+ +
+
+ +
+ +
+ +

The tag suffix.

+ +
+
+ +
+
+ + + + +
size_t yaml_emitter_s::suffix_length
+
+
+ +

The tag suffix length.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::tag_data
+
+
+ +

Tag analysis.

+ +
+
+ +
+ +
+ +

The scalar value.

+ +
+
+ +
+
+ + + + +
size_t yaml_emitter_s::length
+
+
+ +

The scalar length.

+ +
+
+ +
+ +
+ +

The output style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_emitter_s::scalar_data
+
+
+ +

Scalar analysis.

+ +
+
+ +
+ +
+ +

The number of references.

+ +
+
+ +
+
+ + + + +
int yaml_emitter_s::anchor
+
+
+ +

The anchor id.

+ +
+
+ +
+
+ + + + +
struct { ... } * yaml_emitter_s::anchors
+
+
+ +

The information associated with the document nodes.

+ +
+
+ +
+ +
+ +

The last assigned anchor id.

+ +
+
+ +
+ +
+ +

The currently emitted document.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__event__s.html b/libyaml/doc/html/structyaml__event__s.html new file mode 100644 index 00000000..dd7fe30d --- /dev/null +++ b/libyaml/doc/html/structyaml__event__s.html @@ -0,0 +1,525 @@ + + + + + +yaml: yaml_event_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_event_s Struct Reference
+
+
+ +

The event structure. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

yaml_event_type_t type
 The event type.
union {
   struct {
      yaml_encoding_t   encoding
 The document encoding.
   }   stream_start
 The stream parameters (for YAML_STREAM_START_EVENT).
   struct {
      yaml_version_directive_t *   version_directive
 The version directive.
      struct {
         yaml_tag_directive_t *   start
 The beginning of the tag directives list.
         yaml_tag_directive_t *   end
 The end of the tag directives list.
      }   tag_directives
 The list of tag directives.
      int   implicit
 Is the document indicator implicit?
   }   document_start
 The document parameters (for YAML_DOCUMENT_START_EVENT).
   struct {
      int   implicit
 Is the document end indicator implicit?
   }   document_end
 The document end parameters (for YAML_DOCUMENT_END_EVENT).
   struct {
      yaml_char_t *   anchor
 The anchor.
   }   alias
 The alias parameters (for YAML_ALIAS_EVENT).
   struct {
      yaml_char_t *   anchor
 The anchor.
      yaml_char_t *   tag
 The tag.
      yaml_char_t *   value
 The scalar value.
      size_t   length
 The length of the scalar value.
      int   plain_implicit
 Is the tag optional for the plain style?
      int   quoted_implicit
 Is the tag optional for any non-plain style?
      yaml_scalar_style_t   style
 The scalar style.
   }   scalar
 The scalar parameters (for YAML_SCALAR_EVENT).
   struct {
      yaml_char_t *   anchor
 The anchor.
      yaml_char_t *   tag
 The tag.
      int   implicit
 Is the tag optional?
      yaml_sequence_style_t   style
 The sequence style.
   }   sequence_start
 The sequence parameters (for YAML_SEQUENCE_START_EVENT).
   struct {
      yaml_char_t *   anchor
 The anchor.
      yaml_char_t *   tag
 The tag.
      int   implicit
 Is the tag optional?
      yaml_mapping_style_t   style
 The mapping style.
   }   mapping_start
 The mapping parameters (for YAML_MAPPING_START_EVENT).
data
 The event data.
yaml_mark_t start_mark
 The beginning of the event.
yaml_mark_t end_mark
 The end of the event.
+

Detailed Description

+

The event structure.

+

Field Documentation

+ +
+ +
+ +

The event type.

+ +
+
+ +
+ +
+ +

The document encoding.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::stream_start
+
+
+ +

The stream parameters (for YAML_STREAM_START_EVENT).

+ +
+
+ +
+ +
+ +

The version directive.

+ +
+
+ +
+ +
+ +

The beginning of the tag directives list.

+ +
+
+ +
+ +
+ +

The end of the tag directives list.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::tag_directives
+
+
+ +

The list of tag directives.

+ +
+
+ +
+
+ + + + +
int yaml_event_s::implicit
+
+
+ +

Is the document indicator implicit?

+

Is the tag optional?

+

Is the document end indicator implicit?

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::document_start
+
+
+ +

The document parameters (for YAML_DOCUMENT_START_EVENT).

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::document_end
+
+
+ +

The document end parameters (for YAML_DOCUMENT_END_EVENT).

+ +
+
+ +
+ +
+ +

The anchor.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::alias
+
+
+ +

The alias parameters (for YAML_ALIAS_EVENT).

+ +
+
+ +
+ +
+ +

The tag.

+ +
+
+ +
+ +
+ +

The scalar value.

+ +
+
+ +
+
+ + + + +
size_t yaml_event_s::length
+
+
+ +

The length of the scalar value.

+ +
+
+ +
+ +
+ +

The scalar style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::scalar
+
+
+ +

The scalar parameters (for YAML_SCALAR_EVENT).

+ +
+
+ +
+ +
+ +

The sequence style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::sequence_start
+
+
+ +

The sequence parameters (for YAML_SEQUENCE_START_EVENT).

+ +
+
+ +
+ +
+ +

The mapping style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_event_s::mapping_start
+
+
+ +

The mapping parameters (for YAML_MAPPING_START_EVENT).

+ +
+
+ +
+
+ + + + +
union { ... } yaml_event_s::data
+
+
+ +

The event data.

+ +
+
+ +
+ +
+ +

The beginning of the event.

+ +
+
+ +
+ +
+ +

The end of the event.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__mark__s.html b/libyaml/doc/html/structyaml__mark__s.html new file mode 100644 index 00000000..d9c57a42 --- /dev/null +++ b/libyaml/doc/html/structyaml__mark__s.html @@ -0,0 +1,137 @@ + + + + + +yaml: yaml_mark_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_mark_s Struct Reference
+
+
+ +

The pointer position. + More...

+ +

#include <yaml.h>

+ + + + + + + + +

+Data Fields

size_t index
 The position index.
size_t line
 The position line.
size_t column
 The position column.
+

Detailed Description

+

The pointer position.

+

Field Documentation

+ +
+
+ + + + +
size_t yaml_mark_s::index
+
+
+ +

The position index.

+ +
+
+ +
+
+ + + + +
size_t yaml_mark_s::line
+
+
+ +

The position line.

+ +
+
+ +
+
+ + + + +
size_t yaml_mark_s::column
+
+
+ +

The position column.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__node__pair__s.html b/libyaml/doc/html/structyaml__node__pair__s.html new file mode 100644 index 00000000..2310e24a --- /dev/null +++ b/libyaml/doc/html/structyaml__node__pair__s.html @@ -0,0 +1,120 @@ + + + + + +yaml: yaml_node_pair_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_node_pair_s Struct Reference
+
+
+ +

An element of a mapping node. + More...

+ +

#include <yaml.h>

+ + + + + + +

+Data Fields

int key
 The key of the element.
int value
 The value of the element.
+

Detailed Description

+

An element of a mapping node.

+

Field Documentation

+ +
+
+ + + + +
int yaml_node_pair_s::key
+
+
+ +

The key of the element.

+ +
+
+ +
+
+ + + + +
int yaml_node_pair_s::value
+
+
+ +

The value of the element.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__node__s.html b/libyaml/doc/html/structyaml__node__s.html new file mode 100644 index 00000000..de540fb8 --- /dev/null +++ b/libyaml/doc/html/structyaml__node__s.html @@ -0,0 +1,449 @@ + + + + + +yaml: yaml_node_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_node_s Struct Reference
+
+
+ +

The node structure. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

yaml_node_type_t type
 The node type.
yaml_char_ttag
 The node tag.
union {
   struct {
      yaml_char_t *   value
 The scalar value.
      size_t   length
 The length of the scalar value.
      yaml_scalar_style_t   style
 The scalar style.
   }   scalar
 The scalar parameters (for YAML_SCALAR_NODE).
   struct {
      struct {
         yaml_node_item_t *   start
 The beginning of the stack.
         yaml_node_item_t *   end
 The end of the stack.
         yaml_node_item_t *   top
 The top of the stack.
      }   items
 The stack of sequence items.
      yaml_sequence_style_t   style
 The sequence style.
   }   sequence
 The sequence parameters (for YAML_SEQUENCE_NODE).
   struct {
      struct {
         yaml_node_pair_t *   start
 The beginning of the stack.
         yaml_node_pair_t *   end
 The end of the stack.
         yaml_node_pair_t *   top
 The top of the stack.
      }   pairs
 The stack of mapping pairs (key, value).
      yaml_mapping_style_t   style
 The mapping style.
   }   mapping
 The mapping parameters (for YAML_MAPPING_NODE).
data
 The node data.
yaml_mark_t start_mark
 The beginning of the node.
yaml_mark_t end_mark
 The end of the node.
+

Detailed Description

+

The node structure.

+

Field Documentation

+ +
+ +
+ +

The node type.

+ +
+
+ +
+ +
+ +

The node tag.

+ +
+
+ +
+ +
+ +

The scalar value.

+ +
+
+ +
+
+ + + + +
size_t yaml_node_s::length
+
+
+ +

The length of the scalar value.

+ +
+
+ +
+ +
+ +

The scalar style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_node_s::scalar
+
+
+ +

The scalar parameters (for YAML_SCALAR_NODE).

+ +
+
+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_node_s::items
+
+
+ +

The stack of sequence items.

+ +
+
+ +
+ +
+ +

The sequence style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_node_s::sequence
+
+
+ +

The sequence parameters (for YAML_SEQUENCE_NODE).

+ +
+
+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_node_s::pairs
+
+
+ +

The stack of mapping pairs (key, value).

+ +
+
+ +
+ +
+ +

The mapping style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_node_s::mapping
+
+
+ +

The mapping parameters (for YAML_MAPPING_NODE).

+ +
+
+ +
+
+ + + + +
union { ... } yaml_node_s::data
+
+
+ +

The node data.

+ +
+
+ +
+ +
+ +

The beginning of the node.

+ +
+
+ +
+ +
+ +

The end of the node.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__parser__s.html b/libyaml/doc/html/structyaml__parser__s.html new file mode 100644 index 00000000..60fe2a8c --- /dev/null +++ b/libyaml/doc/html/structyaml__parser__s.html @@ -0,0 +1,1248 @@ + + + + + +yaml: yaml_parser_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+
+
yaml_parser_s Struct Reference
+
+
+ +

The parser structure. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

const unsigned char * start
 The string start pointer.
const unsigned char * end
 The string end pointer.
const unsigned char * current
 The string current position.
struct {
   const unsigned char *   start
 The string start pointer.
   const unsigned char *   end
 The string end pointer.
   const unsigned char *   current
 The string current position.
string
 String input data.
FILE * file
 File input data.
yaml_char_tstart
 The beginning of the buffer.
yaml_char_tend
 The end of the buffer.
yaml_char_tpointer
 The current position of the buffer.
yaml_char_tlast
 The last filled position of the buffer.
unsigned char * start
 The beginning of the buffer.
unsigned char * end
 The end of the buffer.
unsigned char * pointer
 The current position of the buffer.
unsigned char * last
 The last filled position of the buffer.
yaml_token_tstart
 The beginning of the tokens queue.
yaml_token_tend
 The end of the tokens queue.
yaml_token_thead
 The head of the tokens queue.
yaml_token_ttail
 The tail of the tokens queue.
int * start
 The beginning of the stack.
int * end
 The end of the stack.
int * top
 The top of the stack.
yaml_simple_key_tstart
 The beginning of the stack.
yaml_simple_key_tend
 The end of the stack.
yaml_simple_key_ttop
 The top of the stack.
yaml_parser_state_tstart
 The beginning of the stack.
yaml_parser_state_tend
 The end of the stack.
yaml_parser_state_ttop
 The top of the stack.
yaml_mark_tstart
 The beginning of the stack.
yaml_mark_tend
 The end of the stack.
yaml_mark_ttop
 The top of the stack.
yaml_tag_directive_tstart
 The beginning of the list.
yaml_tag_directive_tend
 The end of the list.
yaml_tag_directive_ttop
 The top of the list.
yaml_alias_data_tstart
 The beginning of the list.
yaml_alias_data_tend
 The end of the list.
yaml_alias_data_ttop
 The top of the list.
Error handling
yaml_error_type_t error
 Error type.
const char * problem
 Error description.
size_t problem_offset
 The byte about which the problem occured.
int problem_value
 The problematic value (-1 is none).
yaml_mark_t problem_mark
 The problem position.
const char * context
 The error context.
yaml_mark_t context_mark
 The context position.
Reader stuff
yaml_read_handler_tread_handler
 Read handler.
void * read_handler_data
 A pointer for passing to the read handler.
union {
   struct {
      const unsigned char *   start
 The string start pointer.
      const unsigned char *   end
 The string end pointer.
      const unsigned char *   current
 The string current position.
   }   string
 String input data.
   FILE *   file
 File input data.
input
 Standard (string or file) input data.
+int eof
 EOF flag.
struct {
   yaml_char_t *   start
 The beginning of the buffer.
   yaml_char_t *   end
 The end of the buffer.
   yaml_char_t *   pointer
 The current position of the buffer.
   yaml_char_t *   last
 The last filled position of the buffer.
buffer
 The working buffer.
+size_t unread
struct {
   unsigned char *   start
 The beginning of the buffer.
   unsigned char *   end
 The end of the buffer.
   unsigned char *   pointer
 The current position of the buffer.
   unsigned char *   last
 The last filled position of the buffer.
raw_buffer
 The raw buffer.
yaml_encoding_t encoding
 The input encoding.
size_t offset
 The offset of the current position (in bytes).
yaml_mark_t mark
 The mark of the current position.
Scanner stuff
+int stream_start_produced
 Have we started to scan the input stream?
+int stream_end_produced
 Have we reached the end of the input stream?
int flow_level
 The number of unclosed '[' and '{' indicators.
struct {
   yaml_token_t *   start
 The beginning of the tokens queue.
   yaml_token_t *   end
 The end of the tokens queue.
   yaml_token_t *   head
 The head of the tokens queue.
   yaml_token_t *   tail
 The tail of the tokens queue.
tokens
 The tokens queue.
size_t tokens_parsed
 The number of tokens fetched from the queue.
+int token_available
struct {
   int *   start
 The beginning of the stack.
   int *   end
 The end of the stack.
   int *   top
 The top of the stack.
indents
 The indentation levels stack.
int indent
 The current indentation level.
+int simple_key_allowed
 May a simple key occur at the current position?
struct {
   yaml_simple_key_t *   start
 The beginning of the stack.
   yaml_simple_key_t *   end
 The end of the stack.
   yaml_simple_key_t *   top
 The top of the stack.
simple_keys
 The stack of simple keys.
Parser stuff
struct {
   yaml_parser_state_t *   start
 The beginning of the stack.
   yaml_parser_state_t *   end
 The end of the stack.
   yaml_parser_state_t *   top
 The top of the stack.
states
 The parser states stack.
yaml_parser_state_t state
 The current parser state.
struct {
   yaml_mark_t *   start
 The beginning of the stack.
   yaml_mark_t *   end
 The end of the stack.
   yaml_mark_t *   top
 The top of the stack.
marks
 The stack of marks.
struct {
   yaml_tag_directive_t *   start
 The beginning of the list.
   yaml_tag_directive_t *   end
 The end of the list.
   yaml_tag_directive_t *   top
 The top of the list.
tag_directives
 The list of TAG directives.
Dumper stuff
struct {
   yaml_alias_data_t *   start
 The beginning of the list.
   yaml_alias_data_t *   end
 The end of the list.
   yaml_alias_data_t *   top
 The top of the list.
aliases
 The alias data.
yaml_document_tdocument
 The currently parsed document.
+

Detailed Description

+

The parser structure.

+

All members are internal. Manage the structure using the yaml_parser_ family of functions.

+

Field Documentation

+ +
+ +
+ +

Error type.

+ +
+
+ +
+
+ + + + +
const char* yaml_parser_s::problem
+
+
+ +

Error description.

+ +
+
+ +
+
+ + + + +
size_t yaml_parser_s::problem_offset
+
+
+ +

The byte about which the problem occured.

+ +
+
+ +
+ +
+ +

The problematic value (-1 is none).

+ +
+
+ +
+ +
+ +

The problem position.

+ +
+
+ +
+
+ + + + +
const char* yaml_parser_s::context
+
+
+ +

The error context.

+ +
+
+ +
+ +
+ +

The context position.

+ +
+
+ +
+ +
+ +

Read handler.

+ +
+
+ +
+ +
+ +

A pointer for passing to the read handler.

+ +
+
+ +
+
+ + + + +
const unsigned char* yaml_parser_s::start
+
+
+ +

The string start pointer.

+ +
+
+ +
+
+ + + + +
const unsigned char* yaml_parser_s::end
+
+
+ +

The string end pointer.

+ +
+
+ +
+
+ + + + +
const unsigned char* yaml_parser_s::current
+
+
+ +

The string current position.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::string
+
+
+ +

String input data.

+ +
+
+ +
+
+ + + + +
FILE* yaml_parser_s::file
+
+
+ +

File input data.

+ +
+
+ +
+
+ + + + +
union { ... } yaml_parser_s::input
+
+
+ +

Standard (string or file) input data.

+ +
+
+ +
+ +
+ +

The beginning of the buffer.

+ +
+
+ +
+ +
+ +

The end of the buffer.

+ +
+
+ +
+ +
+ +

The current position of the buffer.

+ +
+
+ +
+ +
+ +

The last filled position of the buffer.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::buffer
+
+
+ +

The working buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_parser_s::start
+
+
+ +

The beginning of the buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_parser_s::end
+
+
+ +

The end of the buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_parser_s::pointer
+
+
+ +

The current position of the buffer.

+ +
+
+ +
+
+ + + + +
unsigned char* yaml_parser_s::last
+
+
+ +

The last filled position of the buffer.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::raw_buffer
+
+
+ +

The raw buffer.

+ +
+
+ +
+ +
+ +

The input encoding.

+ +
+
+ +
+
+ + + + +
size_t yaml_parser_s::offset
+
+
+ +

The offset of the current position (in bytes).

+ +
+
+ +
+ +
+ +

The mark of the current position.

+ +
+
+ +
+
+ + + + +
int yaml_parser_s::flow_level
+
+
+ +

The number of unclosed '[' and '{' indicators.

+ +
+
+ +
+ +
+ +

The beginning of the tokens queue.

+ +
+
+ +
+ +
+ +

The end of the tokens queue.

+ +
+
+ +
+ +
+ +

The head of the tokens queue.

+ +
+
+ +
+ +
+ +

The tail of the tokens queue.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::tokens
+
+
+ +

The tokens queue.

+ +
+
+ +
+
+ + + + +
size_t yaml_parser_s::tokens_parsed
+
+
+ +

The number of tokens fetched from the queue.

+ +
+
+ +
+
+ + + + +
int* yaml_parser_s::start
+
+
+ +

The beginning of the stack.

+ +
+
+ +
+
+ + + + +
int* yaml_parser_s::end
+
+
+ +

The end of the stack.

+ +
+
+ +
+
+ + + + +
int* yaml_parser_s::top
+
+
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::indents
+
+
+ +

The indentation levels stack.

+ +
+
+ +
+
+ + + + +
int yaml_parser_s::indent
+
+
+ +

The current indentation level.

+ +
+
+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::simple_keys
+
+
+ +

The stack of simple keys.

+ +
+
+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::states
+
+
+ +

The parser states stack.

+ +
+
+ +
+ +
+ +

The current parser state.

+ +
+
+ +
+ +
+ +

The beginning of the stack.

+ +
+
+ +
+ +
+ +

The end of the stack.

+ +
+
+ +
+ +
+ +

The top of the stack.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::marks
+
+
+ +

The stack of marks.

+ +
+
+ +
+ +
+ +

The beginning of the list.

+ +
+
+ +
+ +
+ +

The end of the list.

+ +
+
+ +
+ +
+ +

The top of the list.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::tag_directives
+
+
+ +

The list of TAG directives.

+ +
+
+ +
+ +
+ +

The beginning of the list.

+ +
+
+ +
+ +
+ +

The end of the list.

+ +
+
+ +
+ +
+ +

The top of the list.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_parser_s::aliases
+
+
+ +

The alias data.

+ +
+
+ +
+ +
+ +

The currently parsed document.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__simple__key__s.html b/libyaml/doc/html/structyaml__simple__key__s.html new file mode 100644 index 00000000..8e4017e9 --- /dev/null +++ b/libyaml/doc/html/structyaml__simple__key__s.html @@ -0,0 +1,126 @@ + + + + + +yaml: yaml_simple_key_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_simple_key_s Struct Reference
+
+
+ +

This structure holds information about a potential simple key. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + +

+Data Fields

+int possible
 Is a simple key possible?
+int required
 Is a simple key required?
size_t token_number
 The number of the token.
yaml_mark_t mark
 The position mark.
+

Detailed Description

+

This structure holds information about a potential simple key.

+

Field Documentation

+ +
+ +
+ +

The number of the token.

+ +
+
+ +
+ +
+ +

The position mark.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__tag__directive__s.html b/libyaml/doc/html/structyaml__tag__directive__s.html new file mode 100644 index 00000000..0c40dc4f --- /dev/null +++ b/libyaml/doc/html/structyaml__tag__directive__s.html @@ -0,0 +1,120 @@ + + + + + +yaml: yaml_tag_directive_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_tag_directive_s Struct Reference
+
+
+ +

The tag directive data. + More...

+ +

#include <yaml.h>

+ + + + + + +

+Data Fields

yaml_char_thandle
 The tag handle.
yaml_char_tprefix
 The tag prefix.
+

Detailed Description

+

The tag directive data.

+

Field Documentation

+ +
+ +
+ +

The tag handle.

+ +
+
+ +
+ +
+ +

The tag prefix.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__token__s.html b/libyaml/doc/html/structyaml__token__s.html new file mode 100644 index 00000000..15a47fa9 --- /dev/null +++ b/libyaml/doc/html/structyaml__token__s.html @@ -0,0 +1,442 @@ + + + + + +yaml: yaml_token_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_token_s Struct Reference
+
+
+ +

The token structure. + More...

+ +

#include <yaml.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

yaml_token_type_t type
 The token type.
union {
   struct {
      yaml_encoding_t   encoding
 The stream encoding.
   }   stream_start
 The stream start (for YAML_STREAM_START_TOKEN).
   struct {
      yaml_char_t *   value
 The alias value.
   }   alias
 The alias (for YAML_ALIAS_TOKEN).
   struct {
      yaml_char_t *   value
 The anchor value.
   }   anchor
 The anchor (for YAML_ANCHOR_TOKEN).
   struct {
      yaml_char_t *   handle
 The tag handle.
      yaml_char_t *   suffix
 The tag suffix.
   }   tag
 The tag (for YAML_TAG_TOKEN).
   struct {
      yaml_char_t *   value
 The scalar value.
      size_t   length
 The length of the scalar value.
      yaml_scalar_style_t   style
 The scalar style.
   }   scalar
 The scalar value (for YAML_SCALAR_TOKEN).
   struct {
      int   major
 The major version number.
      int   minor
 The minor version number.
   }   version_directive
 The version directive (for YAML_VERSION_DIRECTIVE_TOKEN).
   struct {
      yaml_char_t *   handle
 The tag handle.
      yaml_char_t *   prefix
 The tag prefix.
   }   tag_directive
 The tag directive (for YAML_TAG_DIRECTIVE_TOKEN).
data
 The token data.
yaml_mark_t start_mark
 The beginning of the token.
yaml_mark_t end_mark
 The end of the token.
+

Detailed Description

+

The token structure.

+

Field Documentation

+ +
+ +
+ +

The token type.

+ +
+
+ +
+ +
+ +

The stream encoding.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::stream_start
+
+
+ +

The stream start (for YAML_STREAM_START_TOKEN).

+ +
+
+ +
+ +
+ +

The alias value.

+

The scalar value.

+

The anchor value.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::alias
+
+
+ +

The alias (for YAML_ALIAS_TOKEN).

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::anchor
+
+
+ +

The anchor (for YAML_ANCHOR_TOKEN).

+ +
+
+ +
+ +
+ +

The tag handle.

+ +
+
+ +
+ +
+ +

The tag suffix.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::tag
+
+
+ +

The tag (for YAML_TAG_TOKEN).

+ +
+
+ +
+
+ + + + +
size_t yaml_token_s::length
+
+
+ +

The length of the scalar value.

+ +
+
+ +
+ +
+ +

The scalar style.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::scalar
+
+
+ +

The scalar value (for YAML_SCALAR_TOKEN).

+ +
+
+ +
+
+ + + + +
int yaml_token_s::major
+
+
+ +

The major version number.

+ +
+
+ +
+
+ + + + +
int yaml_token_s::minor
+
+
+ +

The minor version number.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::version_directive
+
+
+ +

The version directive (for YAML_VERSION_DIRECTIVE_TOKEN).

+ +
+
+ +
+ +
+ +

The tag prefix.

+ +
+
+ +
+
+ + + + +
struct { ... } yaml_token_s::tag_directive
+
+
+ +

The tag directive (for YAML_TAG_DIRECTIVE_TOKEN).

+ +
+
+ +
+
+ + + + +
union { ... } yaml_token_s::data
+
+
+ +

The token data.

+ +
+
+ +
+ +
+ +

The beginning of the token.

+ +
+
+ +
+ +
+ +

The end of the token.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/structyaml__version__directive__s.html b/libyaml/doc/html/structyaml__version__directive__s.html new file mode 100644 index 00000000..b8faa294 --- /dev/null +++ b/libyaml/doc/html/structyaml__version__directive__s.html @@ -0,0 +1,120 @@ + + + + + +yaml: yaml_version_directive_s Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml_version_directive_s Struct Reference
+
+
+ +

The version directive data. + More...

+ +

#include <yaml.h>

+ + + + + + +

+Data Fields

int major
 The major version number.
int minor
 The minor version number.
+

Detailed Description

+

The version directive data.

+

Field Documentation

+ +
+ +
+ +

The major version number.

+ +
+
+ +
+ +
+ +

The minor version number.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + + + diff --git a/libyaml/doc/html/tab_a.png b/libyaml/doc/html/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..2d99ef23fed78c7683f0b5aa803d937060d288c4 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!Qo)`sjv*C{Z|CmjY;X`^DSv)) z;hc^cTF;t%XWXdwWP5+kt?jQ5uhqKtjd^EY`^^-S;M%tFAj_l)EwVTK)E@1LSD0{e q?a6($SGQTzz1#QBzr0NMKf^0WCX-0bi?u-G89ZJ6T-G@yGywp8?ljB* literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/tab_b.png b/libyaml/doc/html/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..b2c3d2be3c7e518fbca6bb30f571882e72fc506d GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!Qk9-Ajv*C{Z|~mbJ)|JfaM8Xd zIP7xAmLwau9@iXhZTrl-TjWj9jM#?{xt`6uU{<)jb9Suc^QnbhJ(o{ib8=j9u0_mE8M7kgF7f<7W7IEf=8(L_qx|g0H;V7iPxm&Q@G7p8W2Kx&iT|YUM=ITC zY<0Qbr;u&AtXD{o@41wH=7&d8=2Z_{M9Tsa=g*t*@A3H$UOlxZk7?f6RUWpx>Fc_L s#LQ{edY3MpIXkMeV^&YV=9fR%8Jv|Kya=#u06K}m)78&qol`;+0RKEt)&Kwi literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/tab_s.png b/libyaml/doc/html/tab_s.png new file mode 100644 index 0000000000000000000000000000000000000000..978943ac807718de0e69e5a585a8f0a1e5999285 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QZ1e?jv*C{Z|}b5Yzkm-c<7z3 zq^cq0=~}Z;b(!Zvb5Z%sTRFKGlz1=qOFg;myyu?$r`wZb^irPsN1a)6)TwB0r+)wb zPL25;=adu89?fTK`qDR>$D*)b_WOmdKI;Vst02j(hg8%>k literal 0 HcmV?d00001 diff --git a/libyaml/doc/html/tabs.css b/libyaml/doc/html/tabs.css new file mode 100644 index 00000000..21920562 --- /dev/null +++ b/libyaml/doc/html/tabs.css @@ -0,0 +1,59 @@ +.tabs, .tabs2, .tabs3 { + background-image: url('tab_b.png'); + width: 100%; + z-index: 101; + font-size: 13px; +} + +.tabs2 { + font-size: 10px; +} +.tabs3 { + font-size: 9px; +} + +.tablist { + margin: 0; + padding: 0; + display: table; +} + +.tablist li { + float: left; + display: table-cell; + background-image: url('tab_b.png'); + line-height: 36px; + list-style: none; +} + +.tablist a { + display: block; + padding: 0 20px; + font-weight: bold; + background-image:url('tab_s.png'); + background-repeat:no-repeat; + background-position:right; + color: #283A5D; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; + outline: none; +} + +.tabs3 .tablist a { + padding: 0 10px; +} + +.tablist a:hover { + background-image: url('tab_h.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); + text-decoration: none; +} + +.tablist li.current a { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} diff --git a/libyaml/doc/html/yaml_8h.html b/libyaml/doc/html/yaml_8h.html new file mode 100644 index 00000000..8b7631d6 --- /dev/null +++ b/libyaml/doc/html/yaml_8h.html @@ -0,0 +1,546 @@ + + + + + +yaml: yaml.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
yaml +  0.1.5 +
+ +
+
+ + + + +
+
+ +
+
yaml.h File Reference
+
+
+ +

Public interface for libyaml. +More...

+
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  yaml_version_directive_s
 The version directive data. More...
struct  yaml_tag_directive_s
 The tag directive data. More...
struct  yaml_mark_s
 The pointer position. More...
struct  yaml_token_s
 The token structure. More...
struct  yaml_event_s
 The event structure. More...
struct  yaml_node_pair_s
 An element of a mapping node. More...
struct  yaml_node_s
 The node structure. More...
struct  yaml_document_s
 The document structure. More...
struct  yaml_simple_key_s
 This structure holds information about a potential simple key. More...
struct  yaml_alias_data_s
 This structure holds aliases data. More...
struct  yaml_parser_s
 The parser structure. More...
struct  yaml_emitter_s
 The emitter structure. More...

+Defines

#define YAML_DECLARE(type)   type
 The public API declaration.
#define YAML_NULL_TAG   "tag:yaml.org,2002:null"
 The tag !!null with the only possible value: null.
#define YAML_BOOL_TAG   "tag:yaml.org,2002:bool"
 The tag !!bool with the values: true and falce.
#define YAML_STR_TAG   "tag:yaml.org,2002:str"
 The tag !!str for string values.
#define YAML_INT_TAG   "tag:yaml.org,2002:int"
 The tag !!int for integer values.
#define YAML_FLOAT_TAG   "tag:yaml.org,2002:float"
 The tag !!float for float values.
#define YAML_TIMESTAMP_TAG   "tag:yaml.org,2002:timestamp"
 The tag !!timestamp for date and time values.
#define YAML_SEQ_TAG   "tag:yaml.org,2002:seq"
 The tag !!seq is used to denote sequences.
#define YAML_MAP_TAG   "tag:yaml.org,2002:map"
 The tag !!map is used to denote mapping.
#define YAML_DEFAULT_SCALAR_TAG   YAML_STR_TAG
 The default scalar tag is !!str.
#define YAML_DEFAULT_SEQUENCE_TAG   YAML_SEQ_TAG
 The default sequence tag is !!seq.
#define YAML_DEFAULT_MAPPING_TAG   YAML_MAP_TAG
 The default mapping tag is !!map.

+Typedefs

typedef unsigned char yaml_char_t
 The character type (UTF-8 octet).
typedef struct
+yaml_version_directive_s 
yaml_version_directive_t
 The version directive data.
typedef struct yaml_tag_directive_s yaml_tag_directive_t
 The tag directive data.
typedef enum yaml_encoding_e yaml_encoding_t
 The stream encoding.
typedef enum yaml_break_e yaml_break_t
 Line break types.
typedef enum yaml_error_type_e yaml_error_type_t
 Many bad things could happen with the parser and emitter.
typedef struct yaml_mark_s yaml_mark_t
 The pointer position.
typedef enum yaml_scalar_style_e yaml_scalar_style_t
 Scalar styles.
typedef enum yaml_sequence_style_e yaml_sequence_style_t
 Sequence styles.
typedef enum yaml_mapping_style_e yaml_mapping_style_t
 Mapping styles.
typedef enum yaml_token_type_e yaml_token_type_t
 Token types.
typedef struct yaml_token_s yaml_token_t
 The token structure.
typedef enum yaml_event_type_e yaml_event_type_t
 Event types.
typedef struct yaml_event_s yaml_event_t
 The event structure.
typedef enum yaml_node_type_e yaml_node_type_t
 Node types.
typedef struct yaml_node_s yaml_node_t
 The forward definition of a document node structure.
typedef int yaml_node_item_t
 An element of a sequence node.
typedef struct yaml_node_pair_s yaml_node_pair_t
 An element of a mapping node.
typedef struct yaml_document_s yaml_document_t
 The document structure.
typedef int yaml_read_handler_t (void *data, unsigned char *buffer, size_t size, size_t *size_read)
 The prototype of a read handler.
+typedef struct yaml_simple_key_s yaml_simple_key_t
 This structure holds information about a potential simple key.
+typedef enum yaml_parser_state_e yaml_parser_state_t
 The states of the parser.
+typedef struct yaml_alias_data_s yaml_alias_data_t
 This structure holds aliases data.
typedef struct yaml_parser_s yaml_parser_t
 The parser structure.
typedef int yaml_write_handler_t (void *data, unsigned char *buffer, size_t size)
 The prototype of a write handler.
typedef enum yaml_emitter_state_e yaml_emitter_state_t
 The emitter states.
typedef struct yaml_emitter_s yaml_emitter_t
 The emitter structure.

+Enumerations

enum  yaml_encoding_e {
+  YAML_ANY_ENCODING, +
+  YAML_UTF8_ENCODING, +
+  YAML_UTF16LE_ENCODING, +
+  YAML_UTF16BE_ENCODING +
+ }
 The stream encoding. More...
enum  yaml_break_e {
+  YAML_ANY_BREAK, +
+  YAML_CR_BREAK, +
+  YAML_LN_BREAK, +
+  YAML_CRLN_BREAK +
+ }
 Line break types. More...
enum  yaml_error_type_e {
+  YAML_NO_ERROR, +
+  YAML_MEMORY_ERROR, +
+  YAML_READER_ERROR, +
+  YAML_SCANNER_ERROR, +
+  YAML_PARSER_ERROR, +
+  YAML_COMPOSER_ERROR, +
+  YAML_WRITER_ERROR, +
+  YAML_EMITTER_ERROR +
+ }
 Many bad things could happen with the parser and emitter. More...
enum  yaml_scalar_style_e {
+  YAML_ANY_SCALAR_STYLE, +
+  YAML_PLAIN_SCALAR_STYLE, +
+  YAML_SINGLE_QUOTED_SCALAR_STYLE, +
+  YAML_DOUBLE_QUOTED_SCALAR_STYLE, +
+  YAML_LITERAL_SCALAR_STYLE, +
+  YAML_FOLDED_SCALAR_STYLE +
+ }
 Scalar styles. More...
enum  yaml_sequence_style_e {
+  YAML_ANY_SEQUENCE_STYLE, +
+  YAML_BLOCK_SEQUENCE_STYLE, +
+  YAML_FLOW_SEQUENCE_STYLE +
+ }
 Sequence styles. More...
enum  yaml_mapping_style_e {
+  YAML_ANY_MAPPING_STYLE, +
+  YAML_BLOCK_MAPPING_STYLE, +
+  YAML_FLOW_MAPPING_STYLE +
+ }
 Mapping styles. More...
enum  yaml_token_type_e {
+  YAML_NO_TOKEN, +
+  YAML_STREAM_START_TOKEN, +
+  YAML_STREAM_END_TOKEN, +
+  YAML_VERSION_DIRECTIVE_TOKEN, +
+  YAML_TAG_DIRECTIVE_TOKEN, +
+  YAML_DOCUMENT_START_TOKEN, +
+  YAML_DOCUMENT_END_TOKEN, +
+  YAML_BLOCK_SEQUENCE_START_TOKEN, +
+  YAML_BLOCK_MAPPING_START_TOKEN, +
+  YAML_BLOCK_END_TOKEN, +
+  YAML_FLOW_SEQUENCE_START_TOKEN, +
+  YAML_FLOW_SEQUENCE_END_TOKEN, +
+  YAML_FLOW_MAPPING_START_TOKEN, +
+  YAML_FLOW_MAPPING_END_TOKEN, +
+  YAML_BLOCK_ENTRY_TOKEN, +
+  YAML_FLOW_ENTRY_TOKEN, +
+  YAML_KEY_TOKEN, +
+  YAML_VALUE_TOKEN, +
+  YAML_ALIAS_TOKEN, +
+  YAML_ANCHOR_TOKEN, +
+  YAML_TAG_TOKEN, +
+  YAML_SCALAR_TOKEN +
+ }
 Token types. More...
enum  yaml_event_type_e {
+  YAML_NO_EVENT, +
+  YAML_STREAM_START_EVENT, +
+  YAML_STREAM_END_EVENT, +
+  YAML_DOCUMENT_START_EVENT, +
+  YAML_DOCUMENT_END_EVENT, +
+  YAML_ALIAS_EVENT, +
+  YAML_SCALAR_EVENT, +
+  YAML_SEQUENCE_START_EVENT, +
+  YAML_SEQUENCE_END_EVENT, +
+  YAML_MAPPING_START_EVENT, +
+  YAML_MAPPING_END_EVENT +
+ }
 Event types. More...
enum  yaml_node_type_e {
+  YAML_NO_NODE, +
+  YAML_SCALAR_NODE, +
+  YAML_SEQUENCE_NODE, +
+  YAML_MAPPING_NODE +
+ }
 Node types. More...
enum  yaml_parser_state_e {
+  YAML_PARSE_STREAM_START_STATE, +
+  YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, +
+  YAML_PARSE_DOCUMENT_START_STATE, +
+  YAML_PARSE_DOCUMENT_CONTENT_STATE, +
+  YAML_PARSE_DOCUMENT_END_STATE, +
+  YAML_PARSE_BLOCK_NODE_STATE, +
+  YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, +
+  YAML_PARSE_FLOW_NODE_STATE, +
+  YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, +
+  YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, +
+  YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, +
+  YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, +
+  YAML_PARSE_BLOCK_MAPPING_KEY_STATE, +
+  YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, +
+  YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, +
+  YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, +
+  YAML_PARSE_FLOW_MAPPING_KEY_STATE, +
+  YAML_PARSE_FLOW_MAPPING_VALUE_STATE, +
+  YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, +
+  YAML_PARSE_END_STATE +
+ }
 The states of the parser. More...
enum  yaml_emitter_state_e {
+  YAML_EMIT_STREAM_START_STATE, +
+  YAML_EMIT_FIRST_DOCUMENT_START_STATE, +
+  YAML_EMIT_DOCUMENT_START_STATE, +
+  YAML_EMIT_DOCUMENT_CONTENT_STATE, +
+  YAML_EMIT_DOCUMENT_END_STATE, +
+  YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, +
+  YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, +
+  YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, +
+  YAML_EMIT_FLOW_MAPPING_KEY_STATE, +
+  YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, +
+  YAML_EMIT_FLOW_MAPPING_VALUE_STATE, +
+  YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, +
+  YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_KEY_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, +
+  YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, +
+  YAML_EMIT_END_STATE +
+ }
 The emitter states. More...

+Functions

const char * yaml_get_version_string (void)
 Get the library version as a string.
void yaml_get_version (int *major, int *minor, int *patch)
 Get the library version numbers.
void yaml_token_delete (yaml_token_t *token)
 Free any memory allocated for a token object.
int yaml_stream_start_event_initialize (yaml_event_t *event, yaml_encoding_t encoding)
 Create the STREAM-START event.
int yaml_stream_end_event_initialize (yaml_event_t *event)
 Create the STREAM-END event.
int yaml_document_start_event_initialize (yaml_event_t *event, yaml_version_directive_t *version_directive, yaml_tag_directive_t *tag_directives_start, yaml_tag_directive_t *tag_directives_end, int implicit)
 Create the DOCUMENT-START event.
int yaml_document_end_event_initialize (yaml_event_t *event, int implicit)
 Create the DOCUMENT-END event.
int yaml_alias_event_initialize (yaml_event_t *event, yaml_char_t *anchor)
 Create an ALIAS event.
int yaml_scalar_event_initialize (yaml_event_t *event, yaml_char_t *anchor, yaml_char_t *tag, yaml_char_t *value, int length, int plain_implicit, int quoted_implicit, yaml_scalar_style_t style)
 Create a SCALAR event.
int yaml_sequence_start_event_initialize (yaml_event_t *event, yaml_char_t *anchor, yaml_char_t *tag, int implicit, yaml_sequence_style_t style)
 Create a SEQUENCE-START event.
int yaml_sequence_end_event_initialize (yaml_event_t *event)
 Create a SEQUENCE-END event.
int yaml_mapping_start_event_initialize (yaml_event_t *event, yaml_char_t *anchor, yaml_char_t *tag, int implicit, yaml_mapping_style_t style)
 Create a MAPPING-START event.
int yaml_mapping_end_event_initialize (yaml_event_t *event)
 Create a MAPPING-END event.
void yaml_event_delete (yaml_event_t *event)
 Free any memory allocated for an event object.
int yaml_document_initialize (yaml_document_t *document, yaml_version_directive_t *version_directive, yaml_tag_directive_t *tag_directives_start, yaml_tag_directive_t *tag_directives_end, int start_implicit, int end_implicit)
 Create a YAML document.
void yaml_document_delete (yaml_document_t *document)
 Delete a YAML document and all its nodes.
yaml_node_tyaml_document_get_node (yaml_document_t *document, int index)
 Get a node of a YAML document.
yaml_node_tyaml_document_get_root_node (yaml_document_t *document)
 Get the root of a YAML document node.
int yaml_document_add_scalar (yaml_document_t *document, yaml_char_t *tag, yaml_char_t *value, int length, yaml_scalar_style_t style)
 Create a SCALAR node and attach it to the document.
int yaml_document_add_sequence (yaml_document_t *document, yaml_char_t *tag, yaml_sequence_style_t style)
 Create a SEQUENCE node and attach it to the document.
int yaml_document_add_mapping (yaml_document_t *document, yaml_char_t *tag, yaml_mapping_style_t style)
 Create a MAPPING node and attach it to the document.
int yaml_document_append_sequence_item (yaml_document_t *document, int sequence, int item)
 Add an item to a SEQUENCE node.
int yaml_document_append_mapping_pair (yaml_document_t *document, int mapping, int key, int value)
 Add a pair of a key and a value to a MAPPING node.
int yaml_parser_initialize (yaml_parser_t *parser)
 Initialize a parser.
void yaml_parser_delete (yaml_parser_t *parser)
 Destroy a parser.
void yaml_parser_set_input_string (yaml_parser_t *parser, const unsigned char *input, size_t size)
 Set a string input.
void yaml_parser_set_input_file (yaml_parser_t *parser, FILE *file)
 Set a file input.
void yaml_parser_set_input (yaml_parser_t *parser, yaml_read_handler_t *handler, void *data)
 Set a generic input handler.
void yaml_parser_set_encoding (yaml_parser_t *parser, yaml_encoding_t encoding)
 Set the source encoding.
int yaml_parser_scan (yaml_parser_t *parser, yaml_token_t *token)
 Scan the input stream and produce the next token.
int yaml_parser_parse (yaml_parser_t *parser, yaml_event_t *event)
 Parse the input stream and produce the next parsing event.
int yaml_parser_load (yaml_parser_t *parser, yaml_document_t *document)
 Parse the input stream and produce the next YAML document.
int yaml_emitter_initialize (yaml_emitter_t *emitter)
 Initialize an emitter.
void yaml_emitter_delete (yaml_emitter_t *emitter)
 Destroy an emitter.
void yaml_emitter_set_output_string (yaml_emitter_t *emitter, unsigned char *output, size_t size, size_t *size_written)
 Set a string output.
void yaml_emitter_set_output_file (yaml_emitter_t *emitter, FILE *file)
 Set a file output.
void yaml_emitter_set_output (yaml_emitter_t *emitter, yaml_write_handler_t *handler, void *data)
 Set a generic output handler.
void yaml_emitter_set_encoding (yaml_emitter_t *emitter, yaml_encoding_t encoding)
 Set the output encoding.
void yaml_emitter_set_canonical (yaml_emitter_t *emitter, int canonical)
 Set if the output should be in the "canonical" format as in the YAML specification.
void yaml_emitter_set_indent (yaml_emitter_t *emitter, int indent)
 Set the intendation increment.
void yaml_emitter_set_width (yaml_emitter_t *emitter, int width)
 Set the preferred line width.
void yaml_emitter_set_unicode (yaml_emitter_t *emitter, int unicode)
 Set if unescaped non-ASCII characters are allowed.
void yaml_emitter_set_break (yaml_emitter_t *emitter, yaml_break_t line_break)
 Set the preferred line break.
int yaml_emitter_emit (yaml_emitter_t *emitter, yaml_event_t *event)
 Emit an event.
int yaml_emitter_open (yaml_emitter_t *emitter)
 Start a YAML stream.
int yaml_emitter_close (yaml_emitter_t *emitter)
 Finish a YAML stream.
int yaml_emitter_dump (yaml_emitter_t *emitter, yaml_document_t *document)
 Emit a YAML document.
int yaml_emitter_flush (yaml_emitter_t *emitter)
 Flush the accumulated characters to the output.
+

Detailed Description

+

Public interface for libyaml.

+

Include the header file with the code:

+
 #include <yaml.h>
+
+ + + + + + diff --git a/libyaml/include/yaml.h b/libyaml/include/yaml.h new file mode 100644 index 00000000..5a04d36d --- /dev/null +++ b/libyaml/include/yaml.h @@ -0,0 +1,1971 @@ +/** + * @file yaml.h + * @brief Public interface for libyaml. + * + * Include the header file with the code: + * @code + * #include + * @endcode + */ + +#ifndef YAML_H +#define YAML_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @defgroup export Export Definitions + * @{ + */ + +/** The public API declaration. */ + +#ifdef _WIN32 +# if defined(YAML_DECLARE_STATIC) +# define YAML_DECLARE(type) type +# elif defined(YAML_DECLARE_EXPORT) +# define YAML_DECLARE(type) __declspec(dllexport) type +# else +# define YAML_DECLARE(type) __declspec(dllimport) type +# endif +#else +# define YAML_DECLARE(type) type +#endif + +/** @} */ + +/** + * @defgroup version Version Information + * @{ + */ + +/** + * Get the library version as a string. + * + * @returns The function returns the pointer to a static string of the form + * @c "X.Y.Z", where @c X is the major version number, @c Y is a minor version + * number, and @c Z is the patch version number. + */ + +YAML_DECLARE(const char *) +yaml_get_version_string(void); + +/** + * Get the library version numbers. + * + * @param[out] major Major version number. + * @param[out] minor Minor version number. + * @param[out] patch Patch version number. + */ + +YAML_DECLARE(void) +yaml_get_version(int *major, int *minor, int *patch); + +/** @} */ + +/** + * @defgroup basic Basic Types + * @{ + */ + +/** The character type (UTF-8 octet). */ +typedef unsigned char yaml_char_t; + +/** The version directive data. */ +typedef struct yaml_version_directive_s { + /** The major version number. */ + int major; + /** The minor version number. */ + int minor; +} yaml_version_directive_t; + +/** The tag directive data. */ +typedef struct yaml_tag_directive_s { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag prefix. */ + yaml_char_t *prefix; +} yaml_tag_directive_t; + +/** The stream encoding. */ +typedef enum yaml_encoding_e { + /** Let the parser choose the encoding. */ + YAML_ANY_ENCODING, + /** The default UTF-8 encoding. */ + YAML_UTF8_ENCODING, + /** The UTF-16-LE encoding with BOM. */ + YAML_UTF16LE_ENCODING, + /** The UTF-16-BE encoding with BOM. */ + YAML_UTF16BE_ENCODING +} yaml_encoding_t; + +/** Line break types. */ + +typedef enum yaml_break_e { + /** Let the parser choose the break type. */ + YAML_ANY_BREAK, + /** Use CR for line breaks (Mac style). */ + YAML_CR_BREAK, + /** Use LN for line breaks (Unix style). */ + YAML_LN_BREAK, + /** Use CR LN for line breaks (DOS style). */ + YAML_CRLN_BREAK +} yaml_break_t; + +/** Many bad things could happen with the parser and emitter. */ +typedef enum yaml_error_type_e { + /** No error is produced. */ + YAML_NO_ERROR, + + /** Cannot allocate or reallocate a block of memory. */ + YAML_MEMORY_ERROR, + + /** Cannot read or decode the input stream. */ + YAML_READER_ERROR, + /** Cannot scan the input stream. */ + YAML_SCANNER_ERROR, + /** Cannot parse the input stream. */ + YAML_PARSER_ERROR, + /** Cannot compose a YAML document. */ + YAML_COMPOSER_ERROR, + + /** Cannot write to the output stream. */ + YAML_WRITER_ERROR, + /** Cannot emit a YAML stream. */ + YAML_EMITTER_ERROR +} yaml_error_type_t; + +/** The pointer position. */ +typedef struct yaml_mark_s { + /** The position index. */ + size_t index; + + /** The position line. */ + size_t line; + + /** The position column. */ + size_t column; +} yaml_mark_t; + +/** @} */ + +/** + * @defgroup styles Node Styles + * @{ + */ + +/** Scalar styles. */ +typedef enum yaml_scalar_style_e { + /** Let the emitter choose the style. */ + YAML_ANY_SCALAR_STYLE, + + /** The plain scalar style. */ + YAML_PLAIN_SCALAR_STYLE, + + /** The single-quoted scalar style. */ + YAML_SINGLE_QUOTED_SCALAR_STYLE, + /** The double-quoted scalar style. */ + YAML_DOUBLE_QUOTED_SCALAR_STYLE, + + /** The literal scalar style. */ + YAML_LITERAL_SCALAR_STYLE, + /** The folded scalar style. */ + YAML_FOLDED_SCALAR_STYLE +} yaml_scalar_style_t; + +/** Sequence styles. */ +typedef enum yaml_sequence_style_e { + /** Let the emitter choose the style. */ + YAML_ANY_SEQUENCE_STYLE, + + /** The block sequence style. */ + YAML_BLOCK_SEQUENCE_STYLE, + /** The flow sequence style. */ + YAML_FLOW_SEQUENCE_STYLE +} yaml_sequence_style_t; + +/** Mapping styles. */ +typedef enum yaml_mapping_style_e { + /** Let the emitter choose the style. */ + YAML_ANY_MAPPING_STYLE, + + /** The block mapping style. */ + YAML_BLOCK_MAPPING_STYLE, + /** The flow mapping style. */ + YAML_FLOW_MAPPING_STYLE +/* YAML_FLOW_SET_MAPPING_STYLE */ +} yaml_mapping_style_t; + +/** @} */ + +/** + * @defgroup tokens Tokens + * @{ + */ + +/** Token types. */ +typedef enum yaml_token_type_e { + /** An empty token. */ + YAML_NO_TOKEN, + + /** A STREAM-START token. */ + YAML_STREAM_START_TOKEN, + /** A STREAM-END token. */ + YAML_STREAM_END_TOKEN, + + /** A VERSION-DIRECTIVE token. */ + YAML_VERSION_DIRECTIVE_TOKEN, + /** A TAG-DIRECTIVE token. */ + YAML_TAG_DIRECTIVE_TOKEN, + /** A DOCUMENT-START token. */ + YAML_DOCUMENT_START_TOKEN, + /** A DOCUMENT-END token. */ + YAML_DOCUMENT_END_TOKEN, + + /** A BLOCK-SEQUENCE-START token. */ + YAML_BLOCK_SEQUENCE_START_TOKEN, + /** A BLOCK-SEQUENCE-END token. */ + YAML_BLOCK_MAPPING_START_TOKEN, + /** A BLOCK-END token. */ + YAML_BLOCK_END_TOKEN, + + /** A FLOW-SEQUENCE-START token. */ + YAML_FLOW_SEQUENCE_START_TOKEN, + /** A FLOW-SEQUENCE-END token. */ + YAML_FLOW_SEQUENCE_END_TOKEN, + /** A FLOW-MAPPING-START token. */ + YAML_FLOW_MAPPING_START_TOKEN, + /** A FLOW-MAPPING-END token. */ + YAML_FLOW_MAPPING_END_TOKEN, + + /** A BLOCK-ENTRY token. */ + YAML_BLOCK_ENTRY_TOKEN, + /** A FLOW-ENTRY token. */ + YAML_FLOW_ENTRY_TOKEN, + /** A KEY token. */ + YAML_KEY_TOKEN, + /** A VALUE token. */ + YAML_VALUE_TOKEN, + + /** An ALIAS token. */ + YAML_ALIAS_TOKEN, + /** An ANCHOR token. */ + YAML_ANCHOR_TOKEN, + /** A TAG token. */ + YAML_TAG_TOKEN, + /** A SCALAR token. */ + YAML_SCALAR_TOKEN +} yaml_token_type_t; + +/** The token structure. */ +typedef struct yaml_token_s { + + /** The token type. */ + yaml_token_type_t type; + + /** The token data. */ + union { + + /** The stream start (for @c YAML_STREAM_START_TOKEN). */ + struct { + /** The stream encoding. */ + yaml_encoding_t encoding; + } stream_start; + + /** The alias (for @c YAML_ALIAS_TOKEN). */ + struct { + /** The alias value. */ + yaml_char_t *value; + } alias; + + /** The anchor (for @c YAML_ANCHOR_TOKEN). */ + struct { + /** The anchor value. */ + yaml_char_t *value; + } anchor; + + /** The tag (for @c YAML_TAG_TOKEN). */ + struct { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag suffix. */ + yaml_char_t *suffix; + } tag; + + /** The scalar value (for @c YAML_SCALAR_TOKEN). */ + struct { + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The version directive (for @c YAML_VERSION_DIRECTIVE_TOKEN). */ + struct { + /** The major version number. */ + int major; + /** The minor version number. */ + int minor; + } version_directive; + + /** The tag directive (for @c YAML_TAG_DIRECTIVE_TOKEN). */ + struct { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag prefix. */ + yaml_char_t *prefix; + } tag_directive; + + } data; + + /** The beginning of the token. */ + yaml_mark_t start_mark; + /** The end of the token. */ + yaml_mark_t end_mark; + +} yaml_token_t; + +/** + * Free any memory allocated for a token object. + * + * @param[in,out] token A token object. + */ + +YAML_DECLARE(void) +yaml_token_delete(yaml_token_t *token); + +/** @} */ + +/** + * @defgroup events Events + * @{ + */ + +/** Event types. */ +typedef enum yaml_event_type_e { + /** An empty event. */ + YAML_NO_EVENT, + + /** A STREAM-START event. */ + YAML_STREAM_START_EVENT, + /** A STREAM-END event. */ + YAML_STREAM_END_EVENT, + + /** A DOCUMENT-START event. */ + YAML_DOCUMENT_START_EVENT, + /** A DOCUMENT-END event. */ + YAML_DOCUMENT_END_EVENT, + + /** An ALIAS event. */ + YAML_ALIAS_EVENT, + /** A SCALAR event. */ + YAML_SCALAR_EVENT, + + /** A SEQUENCE-START event. */ + YAML_SEQUENCE_START_EVENT, + /** A SEQUENCE-END event. */ + YAML_SEQUENCE_END_EVENT, + + /** A MAPPING-START event. */ + YAML_MAPPING_START_EVENT, + /** A MAPPING-END event. */ + YAML_MAPPING_END_EVENT +} yaml_event_type_t; + +/** The event structure. */ +typedef struct yaml_event_s { + + /** The event type. */ + yaml_event_type_t type; + + /** The event data. */ + union { + + /** The stream parameters (for @c YAML_STREAM_START_EVENT). */ + struct { + /** The document encoding. */ + yaml_encoding_t encoding; + } stream_start; + + /** The document parameters (for @c YAML_DOCUMENT_START_EVENT). */ + struct { + /** The version directive. */ + yaml_version_directive_t *version_directive; + + /** The list of tag directives. */ + struct { + /** The beginning of the tag directives list. */ + yaml_tag_directive_t *start; + /** The end of the tag directives list. */ + yaml_tag_directive_t *end; + } tag_directives; + + /** Is the document indicator implicit? */ + int implicit; + } document_start; + + /** The document end parameters (for @c YAML_DOCUMENT_END_EVENT). */ + struct { + /** Is the document end indicator implicit? */ + int implicit; + } document_end; + + /** The alias parameters (for @c YAML_ALIAS_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + } alias; + + /** The scalar parameters (for @c YAML_SCALAR_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** Is the tag optional for the plain style? */ + int plain_implicit; + /** Is the tag optional for any non-plain style? */ + int quoted_implicit; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The sequence parameters (for @c YAML_SEQUENCE_START_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** Is the tag optional? */ + int implicit; + /** The sequence style. */ + yaml_sequence_style_t style; + } sequence_start; + + /** The mapping parameters (for @c YAML_MAPPING_START_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** Is the tag optional? */ + int implicit; + /** The mapping style. */ + yaml_mapping_style_t style; + } mapping_start; + + } data; + + /** The beginning of the event. */ + yaml_mark_t start_mark; + /** The end of the event. */ + yaml_mark_t end_mark; + +} yaml_event_t; + +/** + * Create the STREAM-START event. + * + * @param[out] event An empty event object. + * @param[in] encoding The stream encoding. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding); + +/** + * Create the STREAM-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event); + +/** + * Create the DOCUMENT-START event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[out] event An empty event object. + * @param[in] version_directive The %YAML directive value or + * @c NULL. + * @param[in] tag_directives_start The beginning of the %TAG + * directives list. + * @param[in] tag_directives_end The end of the %TAG directives + * list. + * @param[in] implicit If the document start indicator is + * implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit); + +/** + * Create the DOCUMENT-END event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[out] event An empty event object. + * @param[in] implicit If the document end indicator is implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit); + +/** + * Create an ALIAS event. + * + * @param[out] event An empty event object. + * @param[in] anchor The anchor value. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor); + +/** + * Create a SCALAR event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or one of the @a plain_implicit and + * @a quoted_implicit flags must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The scalar anchor or @c NULL. + * @param[in] tag The scalar tag or @c NULL. + * @param[in] value The scalar value. + * @param[in] length The length of the scalar value. + * @param[in] plain_implicit If the tag may be omitted for the plain + * style. + * @param[in] quoted_implicit If the tag may be omitted for any + * non-plain style. + * @param[in] style The scalar style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, + yaml_char_t *value, int length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The sequence anchor or @c NULL. + * @param[in] tag The sequence tag or @c NULL. + * @param[in] implicit If the tag may be omitted. + * @param[in] style The sequence style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_sequence_style_t style); + +/** + * Create a SEQUENCE-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event); + +/** + * Create a MAPPING-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The mapping anchor or @c NULL. + * @param[in] tag The mapping tag or @c NULL. + * @param[in] implicit If the tag may be omitted. + * @param[in] style The mapping style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_mapping_style_t style); + +/** + * Create a MAPPING-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event); + +/** + * Free any memory allocated for an event object. + * + * @param[in,out] event An event object. + */ + +YAML_DECLARE(void) +yaml_event_delete(yaml_event_t *event); + +/** @} */ + +/** + * @defgroup nodes Nodes + * @{ + */ + +/** The tag @c !!null with the only possible value: @c null. */ +#define YAML_NULL_TAG "tag:yaml.org,2002:null" +/** The tag @c !!bool with the values: @c true and @c falce. */ +#define YAML_BOOL_TAG "tag:yaml.org,2002:bool" +/** The tag @c !!str for string values. */ +#define YAML_STR_TAG "tag:yaml.org,2002:str" +/** The tag @c !!int for integer values. */ +#define YAML_INT_TAG "tag:yaml.org,2002:int" +/** The tag @c !!float for float values. */ +#define YAML_FLOAT_TAG "tag:yaml.org,2002:float" +/** The tag @c !!timestamp for date and time values. */ +#define YAML_TIMESTAMP_TAG "tag:yaml.org,2002:timestamp" + +/** The tag @c !!seq is used to denote sequences. */ +#define YAML_SEQ_TAG "tag:yaml.org,2002:seq" +/** The tag @c !!map is used to denote mapping. */ +#define YAML_MAP_TAG "tag:yaml.org,2002:map" + +/** The default scalar tag is @c !!str. */ +#define YAML_DEFAULT_SCALAR_TAG YAML_STR_TAG +/** The default sequence tag is @c !!seq. */ +#define YAML_DEFAULT_SEQUENCE_TAG YAML_SEQ_TAG +/** The default mapping tag is @c !!map. */ +#define YAML_DEFAULT_MAPPING_TAG YAML_MAP_TAG + +/** Node types. */ +typedef enum yaml_node_type_e { + /** An empty node. */ + YAML_NO_NODE, + + /** A scalar node. */ + YAML_SCALAR_NODE, + /** A sequence node. */ + YAML_SEQUENCE_NODE, + /** A mapping node. */ + YAML_MAPPING_NODE +} yaml_node_type_t; + +/** The forward definition of a document node structure. */ +typedef struct yaml_node_s yaml_node_t; + +/** An element of a sequence node. */ +typedef int yaml_node_item_t; + +/** An element of a mapping node. */ +typedef struct yaml_node_pair_s { + /** The key of the element. */ + int key; + /** The value of the element. */ + int value; +} yaml_node_pair_t; + +/** The node structure. */ +struct yaml_node_s { + + /** The node type. */ + yaml_node_type_t type; + + /** The node tag. */ + yaml_char_t *tag; + + /** The node data. */ + union { + + /** The scalar parameters (for @c YAML_SCALAR_NODE). */ + struct { + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The sequence parameters (for @c YAML_SEQUENCE_NODE). */ + struct { + /** The stack of sequence items. */ + struct { + /** The beginning of the stack. */ + yaml_node_item_t *start; + /** The end of the stack. */ + yaml_node_item_t *end; + /** The top of the stack. */ + yaml_node_item_t *top; + } items; + /** The sequence style. */ + yaml_sequence_style_t style; + } sequence; + + /** The mapping parameters (for @c YAML_MAPPING_NODE). */ + struct { + /** The stack of mapping pairs (key, value). */ + struct { + /** The beginning of the stack. */ + yaml_node_pair_t *start; + /** The end of the stack. */ + yaml_node_pair_t *end; + /** The top of the stack. */ + yaml_node_pair_t *top; + } pairs; + /** The mapping style. */ + yaml_mapping_style_t style; + } mapping; + + } data; + + /** The beginning of the node. */ + yaml_mark_t start_mark; + /** The end of the node. */ + yaml_mark_t end_mark; + +}; + +/** The document structure. */ +typedef struct yaml_document_s { + + /** The document nodes. */ + struct { + /** The beginning of the stack. */ + yaml_node_t *start; + /** The end of the stack. */ + yaml_node_t *end; + /** The top of the stack. */ + yaml_node_t *top; + } nodes; + + /** The version directive. */ + yaml_version_directive_t *version_directive; + + /** The list of tag directives. */ + struct { + /** The beginning of the tag directives list. */ + yaml_tag_directive_t *start; + /** The end of the tag directives list. */ + yaml_tag_directive_t *end; + } tag_directives; + + /** Is the document start indicator implicit? */ + int start_implicit; + /** Is the document end indicator implicit? */ + int end_implicit; + + /** The beginning of the document. */ + yaml_mark_t start_mark; + /** The end of the document. */ + yaml_mark_t end_mark; + +} yaml_document_t; + +/** + * Create a YAML document. + * + * @param[out] document An empty document object. + * @param[in] version_directive The %YAML directive value or + * @c NULL. + * @param[in] tag_directives_start The beginning of the %TAG + * directives list. + * @param[in] tag_directives_end The end of the %TAG directives + * list. + * @param[in] start_implicit If the document start indicator is + * implicit. + * @param[in] end_implicit If the document end indicator is + * implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_initialize(yaml_document_t *document, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int start_implicit, int end_implicit); + +/** + * Delete a YAML document and all its nodes. + * + * @param[in,out] document A document object. + */ + +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document); + +/** + * Get a node of a YAML document. + * + * The pointer returned by this function is valid until any of the functions + * modifying the documents are called. + * + * @param[in] document A document object. + * @param[in] index The node id. + * + * @returns the node objct or @c NULL if @c node_id is out of range. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_node(yaml_document_t *document, int index); + +/** + * Get the root of a YAML document node. + * + * The root object is the first object added to the document. + * + * The pointer returned by this function is valid until any of the functions + * modifying the documents are called. + * + * An empty document produced by the parser signifies the end of a YAML + * stream. + * + * @param[in] document A document object. + * + * @returns the node object or @c NULL if the document is empty. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_root_node(yaml_document_t *document); + +/** + * Create a SCALAR node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The scalar tag. + * @param[in] value The scalar value. + * @param[in] length The length of the scalar value. + * @param[in] style The scalar style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_scalar(yaml_document_t *document, + yaml_char_t *tag, yaml_char_t *value, int length, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The sequence tag. + * @param[in] style The sequence style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_sequence(yaml_document_t *document, + yaml_char_t *tag, yaml_sequence_style_t style); + +/** + * Create a MAPPING node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The sequence tag. + * @param[in] style The sequence style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_mapping(yaml_document_t *document, + yaml_char_t *tag, yaml_mapping_style_t style); + +/** + * Add an item to a SEQUENCE node. + * + * @param[in,out] document A document object. + * @param[in] sequence The sequence node id. + * @param[in] item The item node id. +* + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence, int item); + +/** + * Add a pair of a key and a value to a MAPPING node. + * + * @param[in,out] document A document object. + * @param[in] mapping The mapping node id. + * @param[in] key The key node id. + * @param[in] value The value node id. +* + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping, int key, int value); + +/** @} */ + +/** + * @defgroup parser Parser Definitions + * @{ + */ + +/** + * The prototype of a read handler. + * + * The read handler is called when the parser needs to read more bytes from the + * source. The handler should write not more than @a size bytes to the @a + * buffer. The number of written bytes should be set to the @a length variable. + * + * @param[in,out] data A pointer to an application data specified by + * yaml_parser_set_input(). + * @param[out] buffer The buffer to write the data from the source. + * @param[in] size The size of the buffer. + * @param[out] size_read The actual number of bytes read from the source. + * + * @returns On success, the handler should return @c 1. If the handler failed, + * the returned value should be @c 0. On EOF, the handler should set the + * @a size_read to @c 0 and return @c 1. + */ + +typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size, + size_t *size_read); + +/** + * This structure holds information about a potential simple key. + */ + +typedef struct yaml_simple_key_s { + /** Is a simple key possible? */ + int possible; + + /** Is a simple key required? */ + int required; + + /** The number of the token. */ + size_t token_number; + + /** The position mark. */ + yaml_mark_t mark; +} yaml_simple_key_t; + +/** + * The states of the parser. + */ +typedef enum yaml_parser_state_e { + /** Expect STREAM-START. */ + YAML_PARSE_STREAM_START_STATE, + /** Expect the beginning of an implicit document. */ + YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, + /** Expect DOCUMENT-START. */ + YAML_PARSE_DOCUMENT_START_STATE, + /** Expect the content of a document. */ + YAML_PARSE_DOCUMENT_CONTENT_STATE, + /** Expect DOCUMENT-END. */ + YAML_PARSE_DOCUMENT_END_STATE, + /** Expect a block node. */ + YAML_PARSE_BLOCK_NODE_STATE, + /** Expect a block node or indentless sequence. */ + YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, + /** Expect a flow node. */ + YAML_PARSE_FLOW_NODE_STATE, + /** Expect the first entry of a block sequence. */ + YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, + /** Expect an entry of a block sequence. */ + YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, + /** Expect an entry of an indentless sequence. */ + YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, + /** Expect the first key of a block mapping. */ + YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, + /** Expect a block mapping key. */ + YAML_PARSE_BLOCK_MAPPING_KEY_STATE, + /** Expect a block mapping value. */ + YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, + /** Expect the first entry of a flow sequence. */ + YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, + /** Expect an entry of a flow sequence. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, + /** Expect a key of an ordered mapping. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, + /** Expect a value of an ordered mapping. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, + /** Expect the and of an ordered mapping entry. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, + /** Expect the first key of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, + /** Expect a key of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_KEY_STATE, + /** Expect a value of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_VALUE_STATE, + /** Expect an empty value of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, + /** Expect nothing. */ + YAML_PARSE_END_STATE +} yaml_parser_state_t; + +/** + * This structure holds aliases data. + */ + +typedef struct yaml_alias_data_s { + /** The anchor. */ + yaml_char_t *anchor; + /** The node id. */ + int index; + /** The anchor mark. */ + yaml_mark_t mark; +} yaml_alias_data_t; + +/** + * The parser structure. + * + * All members are internal. Manage the structure using the @c yaml_parser_ + * family of functions. + */ + +typedef struct yaml_parser_s { + + /** + * @name Error handling + * @{ + */ + + /** Error type. */ + yaml_error_type_t error; + /** Error description. */ + const char *problem; + /** The byte about which the problem occured. */ + size_t problem_offset; + /** The problematic value (@c -1 is none). */ + int problem_value; + /** The problem position. */ + yaml_mark_t problem_mark; + /** The error context. */ + const char *context; + /** The context position. */ + yaml_mark_t context_mark; + + /** + * @} + */ + + /** + * @name Reader stuff + * @{ + */ + + /** Read handler. */ + yaml_read_handler_t *read_handler; + + /** A pointer for passing to the read handler. */ + void *read_handler_data; + + /** Standard (string or file) input data. */ + union { + /** String input data. */ + struct { + /** The string start pointer. */ + const unsigned char *start; + /** The string end pointer. */ + const unsigned char *end; + /** The string current position. */ + const unsigned char *current; + } string; + + /** File input data. */ + FILE *file; + } input; + + /** EOF flag */ + int eof; + + /** The working buffer. */ + struct { + /** The beginning of the buffer. */ + yaml_char_t *start; + /** The end of the buffer. */ + yaml_char_t *end; + /** The current position of the buffer. */ + yaml_char_t *pointer; + /** The last filled position of the buffer. */ + yaml_char_t *last; + } buffer; + + /* The number of unread characters in the buffer. */ + size_t unread; + + /** The raw buffer. */ + struct { + /** The beginning of the buffer. */ + unsigned char *start; + /** The end of the buffer. */ + unsigned char *end; + /** The current position of the buffer. */ + unsigned char *pointer; + /** The last filled position of the buffer. */ + unsigned char *last; + } raw_buffer; + + /** The input encoding. */ + yaml_encoding_t encoding; + + /** The offset of the current position (in bytes). */ + size_t offset; + + /** The mark of the current position. */ + yaml_mark_t mark; + + /** + * @} + */ + + /** + * @name Scanner stuff + * @{ + */ + + /** Have we started to scan the input stream? */ + int stream_start_produced; + + /** Have we reached the end of the input stream? */ + int stream_end_produced; + + /** The number of unclosed '[' and '{' indicators. */ + int flow_level; + + /** The tokens queue. */ + struct { + /** The beginning of the tokens queue. */ + yaml_token_t *start; + /** The end of the tokens queue. */ + yaml_token_t *end; + /** The head of the tokens queue. */ + yaml_token_t *head; + /** The tail of the tokens queue. */ + yaml_token_t *tail; + } tokens; + + /** The number of tokens fetched from the queue. */ + size_t tokens_parsed; + + /* Does the tokens queue contain a token ready for dequeueing. */ + int token_available; + + /** The indentation levels stack. */ + struct { + /** The beginning of the stack. */ + int *start; + /** The end of the stack. */ + int *end; + /** The top of the stack. */ + int *top; + } indents; + + /** The current indentation level. */ + int indent; + + /** May a simple key occur at the current position? */ + int simple_key_allowed; + + /** The stack of simple keys. */ + struct { + /** The beginning of the stack. */ + yaml_simple_key_t *start; + /** The end of the stack. */ + yaml_simple_key_t *end; + /** The top of the stack. */ + yaml_simple_key_t *top; + } simple_keys; + + /** + * @} + */ + + /** + * @name Parser stuff + * @{ + */ + + /** The parser states stack. */ + struct { + /** The beginning of the stack. */ + yaml_parser_state_t *start; + /** The end of the stack. */ + yaml_parser_state_t *end; + /** The top of the stack. */ + yaml_parser_state_t *top; + } states; + + /** The current parser state. */ + yaml_parser_state_t state; + + /** The stack of marks. */ + struct { + /** The beginning of the stack. */ + yaml_mark_t *start; + /** The end of the stack. */ + yaml_mark_t *end; + /** The top of the stack. */ + yaml_mark_t *top; + } marks; + + /** The list of TAG directives. */ + struct { + /** The beginning of the list. */ + yaml_tag_directive_t *start; + /** The end of the list. */ + yaml_tag_directive_t *end; + /** The top of the list. */ + yaml_tag_directive_t *top; + } tag_directives; + + /** + * @} + */ + + /** + * @name Dumper stuff + * @{ + */ + + /** The alias data. */ + struct { + /** The beginning of the list. */ + yaml_alias_data_t *start; + /** The end of the list. */ + yaml_alias_data_t *end; + /** The top of the list. */ + yaml_alias_data_t *top; + } aliases; + + /** The currently parsed document. */ + yaml_document_t *document; + + /** + * @} + */ + +} yaml_parser_t; + +/** + * Initialize a parser. + * + * This function creates a new parser object. An application is responsible + * for destroying the object using the yaml_parser_delete() function. + * + * @param[out] parser An empty parser object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_initialize(yaml_parser_t *parser); + +/** + * Destroy a parser. + * + * @param[in,out] parser A parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser); + +/** + * Set a string input. + * + * Note that the @a input pointer must be valid while the @a parser object + * exists. The application is responsible for destroing @a input after + * destroying the @a parser. + * + * @param[in,out] parser A parser object. + * @param[in] input A source data. + * @param[in] size The length of the source data in bytes. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_string(yaml_parser_t *parser, + const unsigned char *input, size_t size); + +/** + * Set a file input. + * + * @a file should be a file object open for reading. The application is + * responsible for closing the @a file. + * + * @param[in,out] parser A parser object. + * @param[in] file An open file. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file); + +/** + * Set a generic input handler. + * + * @param[in,out] parser A parser object. + * @param[in] handler A read handler. + * @param[in] data Any application data for passing to the read + * handler. + */ + +YAML_DECLARE(void) +yaml_parser_set_input(yaml_parser_t *parser, + yaml_read_handler_t *handler, void *data); + +/** + * Set the source encoding. + * + * @param[in,out] parser A parser object. + * @param[in] encoding The source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding); + +/** + * Scan the input stream and produce the next token. + * + * Call the function subsequently to produce a sequence of tokens corresponding + * to the input stream. The initial token has the type + * @c YAML_STREAM_START_TOKEN while the ending token has the type + * @c YAML_STREAM_END_TOKEN. + * + * An application is responsible for freeing any buffers associated with the + * produced token object using the @c yaml_token_delete function. + * + * An application must not alternate the calls of yaml_parser_scan() with the + * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break + * the parser. + * + * @param[in,out] parser A parser object. + * @param[out] token An empty token object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); + +/** + * Parse the input stream and produce the next parsing event. + * + * Call the function subsequently to produce a sequence of events corresponding + * to the input stream. The initial event has the type + * @c YAML_STREAM_START_EVENT while the ending event has the type + * @c YAML_STREAM_END_EVENT. + * + * An application is responsible for freeing any buffers associated with the + * produced event object using the yaml_event_delete() function. + * + * An application must not alternate the calls of yaml_parser_parse() with the + * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the + * parser. + * + * @param[in,out] parser A parser object. + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); + +/** + * Parse the input stream and produce the next YAML document. + * + * Call this function subsequently to produce a sequence of documents + * constituting the input stream. + * + * If the produced document has no root node, it means that the document + * end has been reached. + * + * An application is responsible for freeing any data associated with the + * produced document object using the yaml_document_delete() function. + * + * An application must not alternate the calls of yaml_parser_load() with the + * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break + * the parser. + * + * @param[in,out] parser A parser object. + * @param[out] document An empty document object. + * + * @return @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); + +/** @} */ + +/** + * @defgroup emitter Emitter Definitions + * @{ + */ + +/** + * The prototype of a write handler. + * + * The write handler is called when the emitter needs to flush the accumulated + * characters to the output. The handler should write @a size bytes of the + * @a buffer to the output. + * + * @param[in,out] data A pointer to an application data specified by + * yaml_emitter_set_output(). + * @param[in] buffer The buffer with bytes to be written. + * @param[in] size The size of the buffer. + * + * @returns On success, the handler should return @c 1. If the handler failed, + * the returned value should be @c 0. + */ + +typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size); + +/** The emitter states. */ +typedef enum yaml_emitter_state_e { + /** Expect STREAM-START. */ + YAML_EMIT_STREAM_START_STATE, + /** Expect the first DOCUMENT-START or STREAM-END. */ + YAML_EMIT_FIRST_DOCUMENT_START_STATE, + /** Expect DOCUMENT-START or STREAM-END. */ + YAML_EMIT_DOCUMENT_START_STATE, + /** Expect the content of a document. */ + YAML_EMIT_DOCUMENT_CONTENT_STATE, + /** Expect DOCUMENT-END. */ + YAML_EMIT_DOCUMENT_END_STATE, + /** Expect the first item of a flow sequence. */ + YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, + /** Expect an item of a flow sequence. */ + YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, + /** Expect the first key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, + /** Expect a key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_KEY_STATE, + /** Expect a value for a simple key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, + /** Expect a value of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_VALUE_STATE, + /** Expect the first item of a block sequence. */ + YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, + /** Expect an item of a block sequence. */ + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, + /** Expect the first key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, + /** Expect the key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_KEY_STATE, + /** Expect a value for a simple key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, + /** Expect a value of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, + /** Expect nothing. */ + YAML_EMIT_END_STATE +} yaml_emitter_state_t; + +/** + * The emitter structure. + * + * All members are internal. Manage the structure using the @c yaml_emitter_ + * family of functions. + */ + +typedef struct yaml_emitter_s { + + /** + * @name Error handling + * @{ + */ + + /** Error type. */ + yaml_error_type_t error; + /** Error description. */ + const char *problem; + + /** + * @} + */ + + /** + * @name Writer stuff + * @{ + */ + + /** Write handler. */ + yaml_write_handler_t *write_handler; + + /** A pointer for passing to the white handler. */ + void *write_handler_data; + + /** Standard (string or file) output data. */ + union { + /** String output data. */ + struct { + /** The buffer pointer. */ + unsigned char *buffer; + /** The buffer size. */ + size_t size; + /** The number of written bytes. */ + size_t *size_written; + } string; + + /** File output data. */ + FILE *file; + } output; + + /** The working buffer. */ + struct { + /** The beginning of the buffer. */ + yaml_char_t *start; + /** The end of the buffer. */ + yaml_char_t *end; + /** The current position of the buffer. */ + yaml_char_t *pointer; + /** The last filled position of the buffer. */ + yaml_char_t *last; + } buffer; + + /** The raw buffer. */ + struct { + /** The beginning of the buffer. */ + unsigned char *start; + /** The end of the buffer. */ + unsigned char *end; + /** The current position of the buffer. */ + unsigned char *pointer; + /** The last filled position of the buffer. */ + unsigned char *last; + } raw_buffer; + + /** The stream encoding. */ + yaml_encoding_t encoding; + + /** + * @} + */ + + /** + * @name Emitter stuff + * @{ + */ + + /** If the output is in the canonical style? */ + int canonical; + /** The number of indentation spaces. */ + int best_indent; + /** The preferred width of the output lines. */ + int best_width; + /** Allow unescaped non-ASCII characters? */ + int unicode; + /** The preferred line break. */ + yaml_break_t line_break; + + /** The stack of states. */ + struct { + /** The beginning of the stack. */ + yaml_emitter_state_t *start; + /** The end of the stack. */ + yaml_emitter_state_t *end; + /** The top of the stack. */ + yaml_emitter_state_t *top; + } states; + + /** The current emitter state. */ + yaml_emitter_state_t state; + + /** The event queue. */ + struct { + /** The beginning of the event queue. */ + yaml_event_t *start; + /** The end of the event queue. */ + yaml_event_t *end; + /** The head of the event queue. */ + yaml_event_t *head; + /** The tail of the event queue. */ + yaml_event_t *tail; + } events; + + /** The stack of indentation levels. */ + struct { + /** The beginning of the stack. */ + int *start; + /** The end of the stack. */ + int *end; + /** The top of the stack. */ + int *top; + } indents; + + /** The list of tag directives. */ + struct { + /** The beginning of the list. */ + yaml_tag_directive_t *start; + /** The end of the list. */ + yaml_tag_directive_t *end; + /** The top of the list. */ + yaml_tag_directive_t *top; + } tag_directives; + + /** The current indentation level. */ + int indent; + + /** The current flow level. */ + int flow_level; + + /** Is it the document root context? */ + int root_context; + /** Is it a sequence context? */ + int sequence_context; + /** Is it a mapping context? */ + int mapping_context; + /** Is it a simple mapping key context? */ + int simple_key_context; + + /** The current line. */ + int line; + /** The current column. */ + int column; + /** If the last character was a whitespace? */ + int whitespace; + /** If the last character was an indentation character (' ', '-', '?', ':')? */ + int indention; + /** If an explicit document end is required? */ + int open_ended; + + /** Anchor analysis. */ + struct { + /** The anchor value. */ + yaml_char_t *anchor; + /** The anchor length. */ + size_t anchor_length; + /** Is it an alias? */ + int alias; + } anchor_data; + + /** Tag analysis. */ + struct { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag handle length. */ + size_t handle_length; + /** The tag suffix. */ + yaml_char_t *suffix; + /** The tag suffix length. */ + size_t suffix_length; + } tag_data; + + /** Scalar analysis. */ + struct { + /** The scalar value. */ + yaml_char_t *value; + /** The scalar length. */ + size_t length; + /** Does the scalar contain line breaks? */ + int multiline; + /** Can the scalar be expessed in the flow plain style? */ + int flow_plain_allowed; + /** Can the scalar be expressed in the block plain style? */ + int block_plain_allowed; + /** Can the scalar be expressed in the single quoted style? */ + int single_quoted_allowed; + /** Can the scalar be expressed in the literal or folded styles? */ + int block_allowed; + /** The output style. */ + yaml_scalar_style_t style; + } scalar_data; + + /** + * @} + */ + + /** + * @name Dumper stuff + * @{ + */ + + /** If the stream was already opened? */ + int opened; + /** If the stream was already closed? */ + int closed; + + /** The information associated with the document nodes. */ + struct { + /** The number of references. */ + int references; + /** The anchor id. */ + int anchor; + /** If the node has been emitted? */ + int serialized; + } *anchors; + + /** The last assigned anchor id. */ + int last_anchor_id; + + /** The currently emitted document. */ + yaml_document_t *document; + + /** + * @} + */ + +} yaml_emitter_t; + +/** + * Initialize an emitter. + * + * This function creates a new emitter object. An application is responsible + * for destroying the object using the yaml_emitter_delete() function. + * + * @param[out] emitter An empty parser object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_initialize(yaml_emitter_t *emitter); + +/** + * Destroy an emitter. + * + * @param[in,out] emitter An emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter); + +/** + * Set a string output. + * + * The emitter will write the output characters to the @a output buffer of the + * size @a size. The emitter will set @a size_written to the number of written + * bytes. If the buffer is smaller than required, the emitter produces the + * YAML_WRITE_ERROR error. + * + * @param[in,out] emitter An emitter object. + * @param[in] output An output buffer. + * @param[in] size The buffer size. + * @param[in] size_written The pointer to save the number of written + * bytes. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_string(yaml_emitter_t *emitter, + unsigned char *output, size_t size, size_t *size_written); + +/** + * Set a file output. + * + * @a file should be a file object open for writing. The application is + * responsible for closing the @a file. + * + * @param[in,out] emitter An emitter object. + * @param[in] file An open file. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file); + +/** + * Set a generic output handler. + * + * @param[in,out] emitter An emitter object. + * @param[in] handler A write handler. + * @param[in] data Any application data for passing to the write + * handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output(yaml_emitter_t *emitter, + yaml_write_handler_t *handler, void *data); + +/** + * Set the output encoding. + * + * @param[in,out] emitter An emitter object. + * @param[in] encoding The output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding); + +/** + * Set if the output should be in the "canonical" format as in the YAML + * specification. + * + * @param[in,out] emitter An emitter object. + * @param[in] canonical If the output is canonical. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical); + +/** + * Set the intendation increment. + * + * @param[in,out] emitter An emitter object. + * @param[in] indent The indentation increment (1 < . < 10). + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent); + +/** + * Set the preferred line width. @c -1 means unlimited. + * + * @param[in,out] emitter An emitter object. + * @param[in] width The preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width); + +/** + * Set if unescaped non-ASCII characters are allowed. + * + * @param[in,out] emitter An emitter object. + * @param[in] unicode If unescaped Unicode characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode); + +/** + * Set the preferred line break. + * + * @param[in,out] emitter An emitter object. + * @param[in] line_break The preferred line break. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break); + +/** + * Emit an event. + * + * The event object may be generated using the yaml_parser_parse() function. + * The emitter takes the responsibility for the event object and destroys its + * content after it is emitted. The event object is destroyed even if the + * function fails. + * + * @param[in,out] emitter An emitter object. + * @param[in,out] event An event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); + +/** + * Start a YAML stream. + * + * This function should be used before yaml_emitter_dump() is called. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter); + +/** + * Finish a YAML stream. + * + * This function should be used after yaml_emitter_dump() is called. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter); + +/** + * Emit a YAML document. + * + * The documen object may be generated using the yaml_parser_load() function + * or the yaml_document_initialize() function. The emitter takes the + * responsibility for the document object and destoys its content after + * it is emitted. The document object is destroyedeven if the function fails. + * + * @param[in,out] emitter An emitter object. + * @param[in,out] document A document object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); + +/** + * Flush the accumulated characters to the output. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef YAML_H */ + diff --git a/libyaml/src/api.c b/libyaml/src/api.c new file mode 100644 index 00000000..c54664d9 --- /dev/null +++ b/libyaml/src/api.c @@ -0,0 +1,1392 @@ + +#include "yaml_private.h" + +/* + * Get the library version. + */ + +YAML_DECLARE(const char *) +yaml_get_version_string(void) +{ + return YAML_VERSION_STRING; +} + +/* + * Get the library version numbers. + */ + +YAML_DECLARE(void) +yaml_get_version(int *major, int *minor, int *patch) +{ + *major = YAML_VERSION_MAJOR; + *minor = YAML_VERSION_MINOR; + *patch = YAML_VERSION_PATCH; +} + +/* + * Allocate a dynamic memory block. + */ + +YAML_DECLARE(void *) +yaml_malloc(size_t size) +{ + return malloc(size ? size : 1); +} + +/* + * Reallocate a dynamic memory block. + */ + +YAML_DECLARE(void *) +yaml_realloc(void *ptr, size_t size) +{ + return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1); +} + +/* + * Free a dynamic memory block. + */ + +YAML_DECLARE(void) +yaml_free(void *ptr) +{ + if (ptr) free(ptr); +} + +/* + * Duplicate a string. + */ + +YAML_DECLARE(yaml_char_t *) +yaml_strdup(const yaml_char_t *str) +{ + if (!str) + return NULL; + + return (yaml_char_t *)_strdup((char *)str); // TC: strdup() > _strdup() +} + +/* + * Extend a string. + */ + +YAML_DECLARE(int) +yaml_string_extend(yaml_char_t **start, + yaml_char_t **pointer, yaml_char_t **end) +{ + yaml_char_t *new_start = yaml_realloc(*start, (*end - *start)*2); + + if (!new_start) return 0; + + memset(new_start + (*end - *start), 0, *end - *start); + + *pointer = new_start + (*pointer - *start); + *end = new_start + (*end - *start)*2; + *start = new_start; + + return 1; +} + +/* + * Append a string B to a string A. + */ + +YAML_DECLARE(int) +yaml_string_join( + yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, + yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end) +{ + if (*b_start == *b_pointer) + return 1; + + while (*a_end - *a_pointer <= *b_pointer - *b_start) { + if (!yaml_string_extend(a_start, a_pointer, a_end)) + return 0; + } + + memcpy(*a_pointer, *b_start, *b_pointer - *b_start); + *a_pointer += *b_pointer - *b_start; + + return 1; +} + +/* + * Extend a stack. + */ + +YAML_DECLARE(int) +yaml_stack_extend(void **start, void **top, void **end) +{ + void *new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2); + + if (!new_start) return 0; + + *top = (char *)new_start + ((char *)*top - (char *)*start); + *end = (char *)new_start + ((char *)*end - (char *)*start)*2; + *start = new_start; + + return 1; +} + +/* + * Extend or move a queue. + */ + +YAML_DECLARE(int) +yaml_queue_extend(void **start, void **head, void **tail, void **end) +{ + /* Check if we need to resize the queue. */ + + if (*start == *head && *tail == *end) { + void *new_start = yaml_realloc(*start, + ((char *)*end - (char *)*start)*2); + + if (!new_start) return 0; + + *head = (char *)new_start + ((char *)*head - (char *)*start); + *tail = (char *)new_start + ((char *)*tail - (char *)*start); + *end = (char *)new_start + ((char *)*end - (char *)*start)*2; + *start = new_start; + } + + /* Check if we need to move the queue at the beginning of the buffer. */ + + if (*tail == *end) { + if (*head != *tail) { + memmove(*start, *head, (char *)*tail - (char *)*head); + } + *tail = (char *)*tail - (char *)*head + (char *)*start; + *head = *start; + } + + return 1; +} + + +/* + * Create a new parser object. + */ + +YAML_DECLARE(int) +yaml_parser_initialize(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + memset(parser, 0, sizeof(yaml_parser_t)); + if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE)) + goto error; + if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE)) + goto error; + if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->states, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_SIZE)) + goto error; + + return 1; + +error: + + BUFFER_DEL(parser, parser->raw_buffer); + BUFFER_DEL(parser, parser->buffer); + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + STACK_DEL(parser, parser->tag_directives); + + return 0; +} + +/* + * Destroy a parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + BUFFER_DEL(parser, parser->raw_buffer); + BUFFER_DEL(parser, parser->buffer); + while (!QUEUE_EMPTY(parser, parser->tokens)) { + yaml_token_delete(&DEQUEUE(parser, parser->tokens)); + } + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, parser->tag_directives); + + memset(parser, 0, sizeof(yaml_parser_t)); +} + +/* + * String read handler. + */ + +static int +yaml_string_read_handler(void *data, unsigned char *buffer, size_t size, + size_t *size_read) +{ + yaml_parser_t *parser = data; + + if (parser->input.string.current == parser->input.string.end) { + *size_read = 0; + return 1; + } + + if (size > (size_t)(parser->input.string.end + - parser->input.string.current)) { + size = parser->input.string.end - parser->input.string.current; + } + + memcpy(buffer, parser->input.string.current, size); + parser->input.string.current += size; + *size_read = size; + return 1; +} + +/* + * File read handler. + */ + +static int +yaml_file_read_handler(void *data, unsigned char *buffer, size_t size, + size_t *size_read) +{ + yaml_parser_t *parser = data; + + *size_read = fread(buffer, 1, size, parser->input.file); + return !ferror(parser->input.file); +} + +/* + * Set a string input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_string(yaml_parser_t *parser, + const unsigned char *input, size_t size) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(input); /* Non-NULL input string expected. */ + + parser->read_handler = yaml_string_read_handler; + parser->read_handler_data = parser; + + parser->input.string.start = input; + parser->input.string.current = input; + parser->input.string.end = input+size; +} + +/* + * Set a file input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(file); /* Non-NULL file object expected. */ + + parser->read_handler = yaml_file_read_handler; + parser->read_handler_data = parser; + + parser->input.file = file; +} + +/* + * Set a generic input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input(yaml_parser_t *parser, + yaml_read_handler_t *handler, void *data) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(handler); /* Non-NULL read handler expected. */ + + parser->read_handler = handler; + parser->read_handler_data = data; +} + +/* + * Set the source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->encoding); /* Encoding is already set or detected. */ + + parser->encoding = encoding; +} + +/* + * Create a new emitter object. + */ + +YAML_DECLARE(int) +yaml_emitter_initialize(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + memset(emitter, 0, sizeof(yaml_emitter_t)); + if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE)) + goto error; + if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_SIZE)) + goto error; + if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_SIZE)) + goto error; + + return 1; + +error: + + BUFFER_DEL(emitter, emitter->buffer); + BUFFER_DEL(emitter, emitter->raw_buffer); + STACK_DEL(emitter, emitter->states); + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + STACK_DEL(emitter, emitter->tag_directives); + + return 0; +} + +/* + * Destroy an emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + BUFFER_DEL(emitter, emitter->buffer); + BUFFER_DEL(emitter, emitter->raw_buffer); + STACK_DEL(emitter, emitter->states); + while (!QUEUE_EMPTY(emitter, emitter->events)) { + yaml_event_delete(&DEQUEUE(emitter, emitter->events)); + } + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + while (!STACK_EMPTY(empty, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(emitter, emitter->tag_directives); + yaml_free(emitter->anchors); + + memset(emitter, 0, sizeof(yaml_emitter_t)); +} + +/* + * String write handler. + */ + +static int +yaml_string_write_handler(void *data, unsigned char *buffer, size_t size) +{ + yaml_emitter_t *emitter = data; + + if (emitter->output.string.size + *emitter->output.string.size_written + < size) { + memcpy(emitter->output.string.buffer + + *emitter->output.string.size_written, + buffer, + emitter->output.string.size + - *emitter->output.string.size_written); + *emitter->output.string.size_written = emitter->output.string.size; + return 0; + } + + memcpy(emitter->output.string.buffer + + *emitter->output.string.size_written, buffer, size); + *emitter->output.string.size_written += size; + return 1; +} + +/* + * File write handler. + */ + +static int +yaml_file_write_handler(void *data, unsigned char *buffer, size_t size) +{ + yaml_emitter_t *emitter = data; + + return (fwrite(buffer, 1, size, emitter->output.file) == size); +} +/* + * Set a string output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_string(yaml_emitter_t *emitter, + unsigned char *output, size_t size, size_t *size_written) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(output); /* Non-NULL output string expected. */ + + emitter->write_handler = yaml_string_write_handler; + emitter->write_handler_data = emitter; + + emitter->output.string.buffer = output; + emitter->output.string.size = size; + emitter->output.string.size_written = size_written; + *size_written = 0; +} + +/* + * Set a file output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(file); /* Non-NULL file object expected. */ + + emitter->write_handler = yaml_file_write_handler; + emitter->write_handler_data = emitter; + + emitter->output.file = file; +} + +/* + * Set a generic output handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output(yaml_emitter_t *emitter, + yaml_write_handler_t *handler, void *data) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(handler); /* Non-NULL handler object expected. */ + + emitter->write_handler = handler; + emitter->write_handler_data = data; +} + +/* + * Set the output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->encoding); /* You can set encoding only once. */ + + emitter->encoding = encoding; +} + +/* + * Set the canonical output style. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->canonical = (canonical != 0); +} + +/* + * Set the indentation increment. + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; +} + +/* + * Set the preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_width = (width >= 0) ? width : -1; +} + +/* + * Set if unescaped non-ASCII characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->unicode = (unicode != 0); +} + +/* + * Set the preferred line break character. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->line_break = line_break; +} + +/* + * Destroy a token object. + */ + +YAML_DECLARE(void) +yaml_token_delete(yaml_token_t *token) +{ + assert(token); /* Non-NULL token object expected. */ + + switch (token->type) + { + case YAML_TAG_DIRECTIVE_TOKEN: + yaml_free(token->data.tag_directive.handle); + yaml_free(token->data.tag_directive.prefix); + break; + + case YAML_ALIAS_TOKEN: + yaml_free(token->data.alias.value); + break; + + case YAML_ANCHOR_TOKEN: + yaml_free(token->data.anchor.value); + break; + + case YAML_TAG_TOKEN: + yaml_free(token->data.tag.handle); + yaml_free(token->data.tag.suffix); + break; + + case YAML_SCALAR_TOKEN: + yaml_free(token->data.scalar.value); + break; + + default: + break; + } + + memset(token, 0, sizeof(yaml_token_t)); +} + +/* + * Check if a string is a valid UTF-8 sequence. + * + * Check 'reader.c' for more details on UTF-8 encoding. + */ + +static int +yaml_check_utf8(yaml_char_t *start, size_t length) +{ + yaml_char_t *end = start+length; + yaml_char_t *pointer = start; + + while (pointer < end) { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t k; + + octet = pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + if (!width) return 0; + if (pointer+width > end) return 0; + for (k = 1; k < width; k ++) { + octet = pointer[k]; + if ((octet & 0xC0) != 0x80) return 0; + value = (value << 6) + (octet & 0x3F); + } + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) return 0; + + pointer += width; + } + + return 1; +} + +/* + * Create STREAM-START. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_START_EVENT_INIT(*event, encoding, mark, mark); + + return 1; +} + +/* + * Create STREAM-END. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create DOCUMENT-START. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives_copy = { NULL, NULL, NULL }; + yaml_tag_directive_t value = { NULL, NULL }; + + assert(event); /* Non-NULL event object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + if (version_directive) { + version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive_copy) goto error; + version_directive_copy->major = version_directive->major; + version_directive_copy->minor = version_directive->minor; + } + + if (tag_directives_start != tag_directives_end) { + yaml_tag_directive_t *tag_directive; + if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) + goto error; + for (tag_directive = tag_directives_start; + tag_directive != tag_directives_end; tag_directive ++) { + assert(tag_directive->handle); + assert(tag_directive->prefix); + if (!yaml_check_utf8(tag_directive->handle, + strlen((char *)tag_directive->handle))) + goto error; + if (!yaml_check_utf8(tag_directive->prefix, + strlen((char *)tag_directive->prefix))) + goto error; + value.handle = yaml_strdup(tag_directive->handle); + value.prefix = yaml_strdup(tag_directive->prefix); + if (!value.handle || !value.prefix) goto error; + if (!PUSH(&context, tag_directives_copy, value)) + goto error; + value.handle = NULL; + value.prefix = NULL; + } + } + + DOCUMENT_START_EVENT_INIT(*event, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.top, + implicit, mark, mark); + + return 1; + +error: + yaml_free(version_directive_copy); + while (!STACK_EMPTY(context, tag_directives_copy)) { + yaml_tag_directive_t value = POP(context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + + return 0; +} + +/* + * Create DOCUMENT-END. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL emitter object is expected. */ + + DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark); + + return 1; +} + +/* + * Create ALIAS. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(anchor); /* Non-NULL anchor is expected. */ + + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0; + + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) + return 0; + + ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark); + + return 1; +} + +/* + * Create SCALAR. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, + yaml_char_t *value, int length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(value); /* Non-NULL anchor is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + if (length < 0) { + length = strlen((char *)value); + } + + if (!yaml_check_utf8(value, length)) goto error; + value_copy = yaml_malloc(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, + plain_implicit, quoted_implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Create SEQUENCE-START. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_sequence_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create SEQUENCE-END. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + SEQUENCE_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create MAPPING-START. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_mapping_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create MAPPING-END. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + MAPPING_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Destroy an event object. + */ + +YAML_DECLARE(void) +yaml_event_delete(yaml_event_t *event) +{ + yaml_tag_directive_t *tag_directive; + + assert(event); /* Non-NULL event object expected. */ + + switch (event->type) + { + case YAML_DOCUMENT_START_EVENT: + yaml_free(event->data.document_start.version_directive); + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive++) { + yaml_free(tag_directive->handle); + yaml_free(tag_directive->prefix); + } + yaml_free(event->data.document_start.tag_directives.start); + break; + + case YAML_ALIAS_EVENT: + yaml_free(event->data.alias.anchor); + break; + + case YAML_SCALAR_EVENT: + yaml_free(event->data.scalar.anchor); + yaml_free(event->data.scalar.tag); + yaml_free(event->data.scalar.value); + break; + + case YAML_SEQUENCE_START_EVENT: + yaml_free(event->data.sequence_start.anchor); + yaml_free(event->data.sequence_start.tag); + break; + + case YAML_MAPPING_START_EVENT: + yaml_free(event->data.mapping_start.anchor); + yaml_free(event->data.mapping_start.tag); + break; + + default: + break; + } + + memset(event, 0, sizeof(yaml_event_t)); +} + +/* + * Create a document object. + */ + +YAML_DECLARE(int) +yaml_document_initialize(yaml_document_t *document, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int start_implicit, int end_implicit) +{ + struct { + yaml_error_type_t error; + } context; + struct { + yaml_node_t *start; + yaml_node_t *end; + yaml_node_t *top; + } nodes = { NULL, NULL, NULL }; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives_copy = { NULL, NULL, NULL }; + yaml_tag_directive_t value = { NULL, NULL }; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(document); /* Non-NULL document object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error; + + if (version_directive) { + version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive_copy) goto error; + version_directive_copy->major = version_directive->major; + version_directive_copy->minor = version_directive->minor; + } + + if (tag_directives_start != tag_directives_end) { + yaml_tag_directive_t *tag_directive; + if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) + goto error; + for (tag_directive = tag_directives_start; + tag_directive != tag_directives_end; tag_directive ++) { + assert(tag_directive->handle); + assert(tag_directive->prefix); + if (!yaml_check_utf8(tag_directive->handle, + strlen((char *)tag_directive->handle))) + goto error; + if (!yaml_check_utf8(tag_directive->prefix, + strlen((char *)tag_directive->prefix))) + goto error; + value.handle = yaml_strdup(tag_directive->handle); + value.prefix = yaml_strdup(tag_directive->prefix); + if (!value.handle || !value.prefix) goto error; + if (!PUSH(&context, tag_directives_copy, value)) + goto error; + value.handle = NULL; + value.prefix = NULL; + } + } + + DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.top, + start_implicit, end_implicit, mark, mark); + + return 1; + +error: + STACK_DEL(&context, nodes); + yaml_free(version_directive_copy); + while (!STACK_EMPTY(&context, tag_directives_copy)) { + yaml_tag_directive_t value = POP(&context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(&context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + + return 0; +} + +/* + * Destroy a document object. + */ + +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document) +{ + struct { + yaml_error_type_t error; + } context; + yaml_tag_directive_t *tag_directive; + + context.error = YAML_NO_ERROR; /* Eliminate a compliler warning. */ + + assert(document); /* Non-NULL document object is expected. */ + + while (!STACK_EMPTY(&context, document->nodes)) { + yaml_node_t node = POP(&context, document->nodes); + yaml_free(node.tag); + switch (node.type) { + case YAML_SCALAR_NODE: + yaml_free(node.data.scalar.value); + break; + case YAML_SEQUENCE_NODE: + STACK_DEL(&context, node.data.sequence.items); + break; + case YAML_MAPPING_NODE: + STACK_DEL(&context, node.data.mapping.pairs); + break; + default: + assert(0); /* Should not happen. */ + } + } + STACK_DEL(&context, document->nodes); + + yaml_free(document->version_directive); + for (tag_directive = document->tag_directives.start; + tag_directive != document->tag_directives.end; + tag_directive++) { + yaml_free(tag_directive->handle); + yaml_free(tag_directive->prefix); + } + yaml_free(document->tag_directives.start); + + memset(document, 0, sizeof(yaml_document_t)); +} + +/** + * Get a document node. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_node(yaml_document_t *document, int index) +{ + assert(document); /* Non-NULL document object is expected. */ + + if (index > 0 && document->nodes.start + index <= document->nodes.top) { + return document->nodes.start + index - 1; + } + return NULL; +} + +/** + * Get the root object. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_root_node(yaml_document_t *document) +{ + assert(document); /* Non-NULL document object is expected. */ + + if (document->nodes.top != document->nodes.start) { + return document->nodes.start; + } + return NULL; +} + +/* + * Add a scalar node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_scalar(yaml_document_t *document, + yaml_char_t *tag, yaml_char_t *value, int length, + yaml_scalar_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + assert(value); /* Non-NULL value is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (length < 0) { + length = strlen((char *)value); + } + + if (!yaml_check_utf8(value, length)) goto error; + value_copy = yaml_malloc(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Add a sequence node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_sequence(yaml_document_t *document, + yaml_char_t *tag, yaml_sequence_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + struct { + yaml_node_item_t *start; + yaml_node_item_t *end; + yaml_node_item_t *top; + } items = { NULL, NULL, NULL }; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error; + + SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, + style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + STACK_DEL(&context, items); + yaml_free(tag_copy); + + return 0; +} + +/* + * Add a mapping node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_mapping(yaml_document_t *document, + yaml_char_t *tag, yaml_mapping_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + struct { + yaml_node_pair_t *start; + yaml_node_pair_t *end; + yaml_node_pair_t *top; + } pairs = { NULL, NULL, NULL }; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error; + + MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, + style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + STACK_DEL(&context, pairs); + yaml_free(tag_copy); + + return 0; +} + +/* + * Append an item to a sequence node. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence, int item) +{ + struct { + yaml_error_type_t error; + } context; + + assert(document); /* Non-NULL document is required. */ + assert(sequence > 0 + && document->nodes.start + sequence <= document->nodes.top); + /* Valid sequence id is required. */ + assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE); + /* A sequence node is required. */ + assert(item > 0 && document->nodes.start + item <= document->nodes.top); + /* Valid item id is required. */ + + if (!PUSH(&context, + document->nodes.start[sequence-1].data.sequence.items, item)) + return 0; + + return 1; +} + +/* + * Append a pair of a key and a value to a mapping node. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping, int key, int value) +{ + struct { + yaml_error_type_t error; + } context; + + yaml_node_pair_t pair; + + assert(document); /* Non-NULL document is required. */ + assert(mapping > 0 + && document->nodes.start + mapping <= document->nodes.top); + /* Valid mapping id is required. */ + assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE); + /* A mapping node is required. */ + assert(key > 0 && document->nodes.start + key <= document->nodes.top); + /* Valid key id is required. */ + assert(value > 0 && document->nodes.start + value <= document->nodes.top); + /* Valid value id is required. */ + + pair.key = key; + pair.value = value; + + if (!PUSH(&context, + document->nodes.start[mapping-1].data.mapping.pairs, pair)) + return 0; + + return 1; +} + + diff --git a/libyaml/src/dumper.c b/libyaml/src/dumper.c new file mode 100644 index 00000000..203c6a70 --- /dev/null +++ b/libyaml/src/dumper.c @@ -0,0 +1,394 @@ + +#include "yaml_private.h" + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter); + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter); + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); + +/* + * Clean up functions. + */ + +static void +yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter); + +/* + * Anchor functions. + */ + +static void +yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index); + +static yaml_char_t * +yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id); + + +/* + * Serialize functions. + */ + +static int +yaml_emitter_dump_node(yaml_emitter_t *emitter, int index); + +static int +yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); + +static int +yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +static int +yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +static int +yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +/* + * Issue a STREAM-START event. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(!emitter->opened); /* Emitter should not be opened yet. */ + + STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark); + + if (!yaml_emitter_emit(emitter, &event)) { + return 0; + } + + emitter->opened = 1; + + return 1; +} + +/* + * Issue a STREAM-END event. + */ + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(emitter->opened); /* Emitter should be opened. */ + + if (emitter->closed) return 1; + + STREAM_END_EVENT_INIT(event, mark, mark); + + if (!yaml_emitter_emit(emitter, &event)) { + return 0; + } + + emitter->closed = 1; + + return 1; +} + +/* + * Dump a YAML document. + */ + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(document); /* Non-NULL emitter object is expected. */ + + emitter->document = document; + + if (!emitter->opened) { + if (!yaml_emitter_open(emitter)) goto error; + } + + if (STACK_EMPTY(emitter, document->nodes)) { + if (!yaml_emitter_close(emitter)) goto error; + yaml_emitter_delete_document_and_anchors(emitter); + return 1; + } + + assert(emitter->opened); /* Emitter should be opened. */ + + emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors)) + * (document->nodes.top - document->nodes.start)); + if (!emitter->anchors) goto error; + memset(emitter->anchors, 0, sizeof(*(emitter->anchors)) + * (document->nodes.top - document->nodes.start)); + + DOCUMENT_START_EVENT_INIT(event, document->version_directive, + document->tag_directives.start, document->tag_directives.end, + document->start_implicit, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) goto error; + + yaml_emitter_anchor_node(emitter, 1); + if (!yaml_emitter_dump_node(emitter, 1)) goto error; + + DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) goto error; + + yaml_emitter_delete_document_and_anchors(emitter); + + return 1; + +error: + + yaml_emitter_delete_document_and_anchors(emitter); + + return 0; +} + +/* + * Clean up the emitter object after a document is dumped. + */ + +static void +yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter) +{ + int index; + + if (!emitter->anchors) { + yaml_document_delete(emitter->document); + emitter->document = NULL; + return; + } + + for (index = 0; emitter->document->nodes.start + index + < emitter->document->nodes.top; index ++) { + yaml_node_t node = emitter->document->nodes.start[index]; + if (!emitter->anchors[index].serialized) { + yaml_free(node.tag); + if (node.type == YAML_SCALAR_NODE) { + yaml_free(node.data.scalar.value); + } + } + if (node.type == YAML_SEQUENCE_NODE) { + STACK_DEL(emitter, node.data.sequence.items); + } + if (node.type == YAML_MAPPING_NODE) { + STACK_DEL(emitter, node.data.mapping.pairs); + } + } + + STACK_DEL(emitter, emitter->document->nodes); + yaml_free(emitter->anchors); + + emitter->anchors = NULL; + emitter->last_anchor_id = 0; + emitter->document = NULL; +} + +/* + * Check the references of a node and assign the anchor id if needed. + */ + +static void +yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index) +{ + yaml_node_t *node = emitter->document->nodes.start + index - 1; + yaml_node_item_t *item; + yaml_node_pair_t *pair; + + emitter->anchors[index-1].references ++; + + if (emitter->anchors[index-1].references == 1) { + switch (node->type) { + case YAML_SEQUENCE_NODE: + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item ++) { + yaml_emitter_anchor_node(emitter, *item); + } + break; + case YAML_MAPPING_NODE: + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair ++) { + yaml_emitter_anchor_node(emitter, pair->key); + yaml_emitter_anchor_node(emitter, pair->value); + } + break; + default: + break; + } + } + + else if (emitter->anchors[index-1].references == 2) { + emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id); + } +} + +/* + * Generate a textual representation for an anchor. + */ + +#define ANCHOR_TEMPLATE "id%03d" +#define ANCHOR_TEMPLATE_LENGTH 16 + +static yaml_char_t * +yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id) +{ + yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH); + + if (!anchor) return NULL; + + sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id); + + return anchor; +} + +/* + * Serialize a node. + */ + +static int +yaml_emitter_dump_node(yaml_emitter_t *emitter, int index) +{ + yaml_node_t *node = emitter->document->nodes.start + index - 1; + int anchor_id = emitter->anchors[index-1].anchor; + yaml_char_t *anchor = NULL; + + if (anchor_id) { + anchor = yaml_emitter_generate_anchor(emitter, anchor_id); + if (!anchor) return 0; + } + + if (emitter->anchors[index-1].serialized) { + return yaml_emitter_dump_alias(emitter, anchor); + } + + emitter->anchors[index-1].serialized = 1; + + switch (node->type) { + case YAML_SCALAR_NODE: + return yaml_emitter_dump_scalar(emitter, node, anchor); + case YAML_SEQUENCE_NODE: + return yaml_emitter_dump_sequence(emitter, node, anchor); + case YAML_MAPPING_NODE: + return yaml_emitter_dump_mapping(emitter, node, anchor); + default: + assert(0); /* Could not happen. */ + break; + } + + return 0; /* Could not happen. */ +} + +/* + * Serialize an alias. + */ + +static int +yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + ALIAS_EVENT_INIT(event, anchor, mark, mark); + + return yaml_emitter_emit(emitter, &event); +} + +/* + * Serialize a scalar. + */ + +static int +yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int plain_implicit = (strcmp((char *)node->tag, + YAML_DEFAULT_SCALAR_TAG) == 0); + int quoted_implicit = (strcmp((char *)node->tag, + YAML_DEFAULT_SCALAR_TAG) == 0); + + SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value, + node->data.scalar.length, plain_implicit, quoted_implicit, + node->data.scalar.style, mark, mark); + + return yaml_emitter_emit(emitter, &event); +} + +/* + * Serialize a sequence. + */ + +static int +yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0); + + yaml_node_item_t *item; + + SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit, + node->data.sequence.style, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item ++) { + if (!yaml_emitter_dump_node(emitter, *item)) return 0; + } + + SEQUENCE_END_EVENT_INIT(event, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + return 1; +} + +/* + * Serialize a mapping. + */ + +static int +yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0); + + yaml_node_pair_t *pair; + + MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit, + node->data.mapping.style, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair ++) { + if (!yaml_emitter_dump_node(emitter, pair->key)) return 0; + if (!yaml_emitter_dump_node(emitter, pair->value)) return 0; + } + + MAPPING_END_EVENT_INIT(event, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + return 1; +} + diff --git a/libyaml/src/emitter.c b/libyaml/src/emitter.c new file mode 100644 index 00000000..c4b56a26 --- /dev/null +++ b/libyaml/src/emitter.c @@ -0,0 +1,2329 @@ + +#include "yaml_private.h" + +/* + * Flush the buffer if needed. + */ + +#define FLUSH(emitter) \ + ((emitter->buffer.pointer+5 < emitter->buffer.end) \ + || yaml_emitter_flush(emitter)) + +/* + * Put a character to the output buffer. + */ + +#define PUT(emitter,value) \ + (FLUSH(emitter) \ + && (*(emitter->buffer.pointer++) = (yaml_char_t)(value), \ + emitter->column ++, \ + 1)) + +/* + * Put a line break to the output buffer. + */ + +#define PUT_BREAK(emitter) \ + (FLUSH(emitter) \ + && ((emitter->line_break == YAML_CR_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\r') : \ + emitter->line_break == YAML_LN_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\n') : \ + emitter->line_break == YAML_CRLN_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\r', \ + *(emitter->buffer.pointer++) = (yaml_char_t) '\n') : 0), \ + emitter->column = 0, \ + emitter->line ++, \ + 1)) + +/* + * Copy a character from a string into buffer. + */ + +#define WRITE(emitter,string) \ + (FLUSH(emitter) \ + && (COPY(emitter->buffer,string), \ + emitter->column ++, \ + 1)) + +/* + * Copy a line break character from a string into buffer. + */ + +#define WRITE_BREAK(emitter,string) \ + (FLUSH(emitter) \ + && (CHECK(string,'\n') ? \ + (PUT_BREAK(emitter), \ + string.pointer ++, \ + 1) : \ + (COPY(emitter->buffer,string), \ + emitter->column = 0, \ + emitter->line ++, \ + 1))) + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Utility functions. + */ + +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem); + +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter); + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates); + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless); + +/* + * State functions. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key); + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Checkers. + */ + +static int +yaml_emitter_check_empty_document(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter); + +static int +yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Processors. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter); + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter); + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter); + +/* + * Analyzers. + */ + +static int +yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive); + +static int +yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive); + +static int +yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias); + +static int +yaml_emitter_analyze_tag(yaml_emitter_t *emitter, + yaml_char_t *tag); + +static int +yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_analyze_event(yaml_emitter_t *emitter, + yaml_event_t *event); + +/* + * Writers. + */ + +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + char *indicator, int need_whitespace, + int is_whitespace, int is_indention); + +static int +yaml_emitter_write_anchor(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_tag_content(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int need_whitespace); + +static int +yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, + yaml_string_t string); + +static int +yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +/* + * Set an emitter error and return 0. + */ + +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem) +{ + emitter->error = YAML_EMITTER_ERROR; + emitter->problem = problem; + + return 0; +} + +/* + * Emit an event. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!ENQUEUE(emitter, emitter->events, *event)) { + yaml_event_delete(event); + return 0; + } + + while (!yaml_emitter_need_more_events(emitter)) { + if (!yaml_emitter_analyze_event(emitter, emitter->events.head)) + return 0; + if (!yaml_emitter_state_machine(emitter, emitter->events.head)) + return 0; + yaml_event_delete(&DEQUEUE(emitter, emitter->events)); + } + + return 1; +} + +/* + * Check if we need to accumulate more events before emitting. + * + * We accumulate extra + * - 1 event for DOCUMENT-START + * - 2 events for SEQUENCE-START + * - 3 events for MAPPING-START + */ + +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter) +{ + int level = 0; + int accumulate = 0; + yaml_event_t *event; + + if (QUEUE_EMPTY(emitter, emitter->events)) + return 1; + + switch (emitter->events.head->type) { + case YAML_DOCUMENT_START_EVENT: + accumulate = 1; + break; + case YAML_SEQUENCE_START_EVENT: + accumulate = 2; + break; + case YAML_MAPPING_START_EVENT: + accumulate = 3; + break; + default: + return 0; + } + + if (emitter->events.tail - emitter->events.head > accumulate) + return 0; + + for (event = emitter->events.head; event != emitter->events.tail; event ++) { + switch (event->type) { + case YAML_STREAM_START_EVENT: + case YAML_DOCUMENT_START_EVENT: + case YAML_SEQUENCE_START_EVENT: + case YAML_MAPPING_START_EVENT: + level += 1; + break; + case YAML_STREAM_END_EVENT: + case YAML_DOCUMENT_END_EVENT: + case YAML_SEQUENCE_END_EVENT: + case YAML_MAPPING_END_EVENT: + level -= 1; + break; + default: + break; + } + if (!level) + return 0; + } + + return 1; +} + +/* + * Append a directive to the directives stack. + */ + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_emitter_set_emitter_error(emitter, + "duplicate %TAG directive"); + } + } + + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + emitter->error = YAML_MEMORY_ERROR; + goto error; + } + + if (!PUSH(emitter, emitter->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); + return 0; +} + +/* + * Increase the indentation level. + */ + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless) +{ + if (!PUSH(emitter, emitter->indents, emitter->indent)) + return 0; + + if (emitter->indent < 0) { + emitter->indent = flow ? emitter->best_indent : 0; + } + else if (!indentless) { + emitter->indent += emitter->best_indent; + } + + return 1; +} + +/* + * State dispatcher. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event) +{ + switch (emitter->state) + { + case YAML_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event); + + case YAML_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 1); + + case YAML_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 0); + + case YAML_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event); + + case YAML_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event); + + case YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 1); + + case YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 0); + + case YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 1); + + case YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 0); + + case YAML_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, + "expected nothing after STREAM-END"); + + default: + assert(1); /* Invalid state. */ + } + + return 0; +} + +/* + * Expect STREAM-START. + */ + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (event->type == YAML_STREAM_START_EVENT) + { + if (!emitter->encoding) { + emitter->encoding = event->data.stream_start.encoding; + } + + if (!emitter->encoding) { + emitter->encoding = YAML_UTF8_ENCODING; + } + + if (emitter->best_indent < 2 || emitter->best_indent > 9) { + emitter->best_indent = 2; + } + + if (emitter->best_width >= 0 + && emitter->best_width <= emitter->best_indent*2) { + emitter->best_width = 80; + } + + if (emitter->best_width < 0) { + emitter->best_width = INT_MAX; + } + + if (!emitter->line_break) { + emitter->line_break = YAML_LN_BREAK; + } + + emitter->indent = -1; + + emitter->line = 0; + emitter->column = 0; + emitter->whitespace = 1; + emitter->indention = 1; + + if (emitter->encoding != YAML_UTF8_ENCODING) { + if (!yaml_emitter_write_bom(emitter)) + return 0; + } + + emitter->state = YAML_EMIT_FIRST_DOCUMENT_START_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected STREAM-START"); +} + +/* + * Expect DOCUMENT-START or STREAM-END. + */ + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (event->type == YAML_DOCUMENT_START_EVENT) + { + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *tag_directive; + int implicit; + + if (event->data.document_start.version_directive) { + if (!yaml_emitter_analyze_version_directive(emitter, + *event->data.document_start.version_directive)) + return 0; + } + + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_analyze_tag_directive(emitter, *tag_directive)) + return 0; + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0)) + return 0; + } + + for (tag_directive = default_tag_directives; + tag_directive->handle; tag_directive ++) { + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 1)) + return 0; + } + + implicit = event->data.document_start.implicit; + if (!first || emitter->canonical) { + implicit = 0; + } + + if ((event->data.document_start.version_directive || + (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end)) && + emitter->open_ended) + { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (event->data.document_start.version_directive) { + implicit = 0; + if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end) { + implicit = 0; + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_write_indicator(emitter, "%TAG", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_tag_handle(emitter, tag_directive->handle, + strlen((char *)tag_directive->handle))) + return 0; + if (!yaml_emitter_write_tag_content(emitter, tag_directive->prefix, + strlen((char *)tag_directive->prefix), 1)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + if (yaml_emitter_check_empty_document(emitter)) { + implicit = 0; + } + + if (!implicit) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "---", 1, 0, 0)) + return 0; + if (emitter->canonical) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE; + + return 1; + } + + else if (event->type == YAML_STREAM_END_EVENT) + { + if (emitter->open_ended) + { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_END_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-START or STREAM-END"); +} + +/* + * Expect the root node. + */ + +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (!PUSH(emitter, emitter->states, YAML_EMIT_DOCUMENT_END_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0); +} + +/* + * Expect DOCUMENT-END. + */ + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (event->type == YAML_DOCUMENT_END_EVENT) + { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!event->data.document_end.implicit) { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_DOCUMENT_START_STATE; + + while (!STACK_EMPTY(emitter, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, + emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-END"); +} + +/* + * + * Expect a flow item node. + */ + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "[", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } + + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "]", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); +} + +/* + * Expect a flow key node. + */ + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "{", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "}", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (!emitter->canonical && yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 0)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +/* + * Expect a flow value node. + */ + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 0)) + return 0; + } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +/* + * Expect a block item node. + */ + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, + (emitter->mapping_context && !emitter->indention))) + return 0; + } + + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "-", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); +} + +/* + * Expect a block key node. + */ + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, 0)) + return 0; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!yaml_emitter_write_indent(emitter)) + return 0; + + if (yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +/* + * Expect a block value node. + */ + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 1)) + return 0; + } + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_KEY_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +/* + * Expect a node. + */ + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key) +{ + emitter->root_context = root; + emitter->sequence_context = sequence; + emitter->mapping_context = mapping; + emitter->simple_key_context = simple_key; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event); + + case YAML_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event); + + case YAML_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event); + + case YAML_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event); + + default: + return yaml_emitter_set_emitter_error(emitter, + "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS"); + } + + return 0; +} + +/* + * Expect ALIAS. + */ + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +/* + * Expect SCALAR. + */ + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_select_scalar_style(emitter, event)) + return 0; + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + if (!yaml_emitter_process_scalar(emitter)) + return 0; + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +/* + * Expect SEQUENCE-START. + */ + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE + || yaml_emitter_check_empty_sequence(emitter)) { + emitter->state = YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE; + } + + return 1; +} + +/* + * Expect MAPPING-START. + */ + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.mapping_start.style == YAML_FLOW_MAPPING_STYLE + || yaml_emitter_check_empty_mapping(emitter)) { + emitter->state = YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE; + } + + return 1; +} + +/* + * Check if the document content is an empty scalar. + */ + +static int +yaml_emitter_check_empty_document(yaml_emitter_t *emitter) +{ + return 0; +} + +/* + * Check if the next events represent an empty sequence. + */ + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter) +{ + if (emitter->events.tail - emitter->events.head < 2) + return 0; + + return (emitter->events.head[0].type == YAML_SEQUENCE_START_EVENT + && emitter->events.head[1].type == YAML_SEQUENCE_END_EVENT); +} + +/* + * Check if the next events represent an empty mapping. + */ + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter) +{ + if (emitter->events.tail - emitter->events.head < 2) + return 0; + + return (emitter->events.head[0].type == YAML_MAPPING_START_EVENT + && emitter->events.head[1].type == YAML_MAPPING_END_EVENT); +} + +/* + * Check if the next node can be expressed as a simple key. + */ + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter) +{ + yaml_event_t *event = emitter->events.head; + size_t length = 0; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + length += emitter->anchor_data.anchor_length; + break; + + case YAML_SCALAR_EVENT: + if (emitter->scalar_data.multiline) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length + + emitter->scalar_data.length; + break; + + case YAML_SEQUENCE_START_EVENT: + if (!yaml_emitter_check_empty_sequence(emitter)) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length; + break; + + case YAML_MAPPING_START_EVENT: + if (!yaml_emitter_check_empty_mapping(emitter)) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length; + break; + + default: + return 0; + } + + if (length > 128) + return 0; + + return 1; +} + +/* + * Determine an acceptable scalar style. + */ + +static int +yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) +{ + yaml_scalar_style_t style = event->data.scalar.style; + int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix); + + if (no_tag && !event->data.scalar.plain_implicit + && !event->data.scalar.quoted_implicit) { + return yaml_emitter_set_emitter_error(emitter, + "neither tag nor implicit flags are specified"); + } + + if (style == YAML_ANY_SCALAR_STYLE) + style = YAML_PLAIN_SCALAR_STYLE; + + if (emitter->canonical) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + + if (emitter->simple_key_context && emitter->scalar_data.multiline) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + + if (style == YAML_PLAIN_SCALAR_STYLE) + { + if ((emitter->flow_level && !emitter->scalar_data.flow_plain_allowed) + || (!emitter->flow_level && !emitter->scalar_data.block_plain_allowed)) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + if (!emitter->scalar_data.length + && (emitter->flow_level || emitter->simple_key_context)) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + if (no_tag && !event->data.scalar.plain_implicit) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + } + + if (style == YAML_SINGLE_QUOTED_SCALAR_STYLE) + { + if (!emitter->scalar_data.single_quoted_allowed) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + } + + if (style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE) + { + if (!emitter->scalar_data.block_allowed + || emitter->flow_level || emitter->simple_key_context) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + } + + if (no_tag && !event->data.scalar.quoted_implicit + && style != YAML_PLAIN_SCALAR_STYLE) + { + emitter->tag_data.handle = (yaml_char_t *)"!"; + emitter->tag_data.handle_length = 1; + } + + emitter->scalar_data.style = style; + + return 1; +} + +/* + * Write an achor. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter) +{ + if (!emitter->anchor_data.anchor) + return 1; + + if (!yaml_emitter_write_indicator(emitter, + (emitter->anchor_data.alias ? "*" : "&"), 1, 0, 0)) + return 0; + + return yaml_emitter_write_anchor(emitter, + emitter->anchor_data.anchor, emitter->anchor_data.anchor_length); +} + +/* + * Write a tag. + */ + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter) +{ + if (!emitter->tag_data.handle && !emitter->tag_data.suffix) + return 1; + + if (emitter->tag_data.handle) + { + if (!yaml_emitter_write_tag_handle(emitter, emitter->tag_data.handle, + emitter->tag_data.handle_length)) + return 0; + if (emitter->tag_data.suffix) { + if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, + emitter->tag_data.suffix_length, 0)) + return 0; + } + } + else + { + if (!yaml_emitter_write_indicator(emitter, "!<", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, + emitter->tag_data.suffix_length, 0)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ">", 0, 0, 0)) + return 0; + } + + return 1; +} + +/* + * Write a scalar. + */ + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter) +{ + switch (emitter->scalar_data.style) + { + case YAML_PLAIN_SCALAR_STYLE: + return yaml_emitter_write_plain_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_SINGLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_single_quoted_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_DOUBLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_double_quoted_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_LITERAL_SCALAR_STYLE: + return yaml_emitter_write_literal_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length); + + case YAML_FOLDED_SCALAR_STYLE: + return yaml_emitter_write_folded_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length); + + default: + assert(1); /* Impossible. */ + } + + return 0; +} + +/* + * Check if a %YAML directive is valid. + */ + +static int +yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive) +{ + if (version_directive.major != 1 || version_directive.minor != 1) { + return yaml_emitter_set_emitter_error(emitter, + "incompatible %YAML directive"); + } + + return 1; +} + +/* + * Check if a %TAG directive is valid. + */ + +static int +yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive) +{ + yaml_string_t handle; + yaml_string_t prefix; + size_t handle_length; + size_t prefix_length; + + handle_length = strlen((char *)tag_directive.handle); + prefix_length = strlen((char *)tag_directive.prefix); + STRING_ASSIGN(handle, tag_directive.handle, handle_length); + STRING_ASSIGN(prefix, tag_directive.prefix, prefix_length); + + if (handle.start == handle.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must not be empty"); + } + + if (handle.start[0] != '!') { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must start with '!'"); + } + + if (handle.end[-1] != '!') { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must end with '!'"); + } + + handle.pointer ++; + + while (handle.pointer < handle.end-1) { + if (!IS_ALPHA(handle)) { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must contain alphanumerical characters only"); + } + MOVE(handle); + } + + if (prefix.start == prefix.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag prefix must not be empty"); + } + + return 1; +} + +/* + * Check if an anchor is valid. + */ + +static int +yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias) +{ + size_t anchor_length; + yaml_string_t string; + + anchor_length = strlen((char *)anchor); + STRING_ASSIGN(string, anchor, anchor_length); + + if (string.start == string.end) { + return yaml_emitter_set_emitter_error(emitter, alias ? + "alias value must not be empty" : + "anchor value must not be empty"); + } + + while (string.pointer != string.end) { + if (!IS_ALPHA(string)) { + return yaml_emitter_set_emitter_error(emitter, alias ? + "alias value must contain alphanumerical characters only" : + "anchor value must contain alphanumerical characters only"); + } + MOVE(string); + } + + emitter->anchor_data.anchor = string.start; + emitter->anchor_data.anchor_length = string.end - string.start; + emitter->anchor_data.alias = alias; + + return 1; +} + +/* + * Check if a tag is valid. + */ + +static int +yaml_emitter_analyze_tag(yaml_emitter_t *emitter, + yaml_char_t *tag) +{ + size_t tag_length; + yaml_string_t string; + yaml_tag_directive_t *tag_directive; + + tag_length = strlen((char *)tag); + STRING_ASSIGN(string, tag, tag_length); + + if (string.start == string.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag value must not be empty"); + } + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + size_t prefix_length = strlen((char *)tag_directive->prefix); + if (prefix_length < (size_t)(string.end - string.start) + && strncmp((char *)tag_directive->prefix, (char *)string.start, + prefix_length) == 0) + { + emitter->tag_data.handle = tag_directive->handle; + emitter->tag_data.handle_length = + strlen((char *)tag_directive->handle); + emitter->tag_data.suffix = string.start + prefix_length; + emitter->tag_data.suffix_length = + (string.end - string.start) - prefix_length; + return 1; + } + } + + emitter->tag_data.suffix = string.start; + emitter->tag_data.suffix_length = string.end - string.start; + + return 1; +} + +/* + * Check if a scalar is valid. + */ + +static int +yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + + int block_indicators = 0; + int flow_indicators = 0; + int line_breaks = 0; + int special_characters = 0; + + int leading_space = 0; + int leading_break = 0; + int trailing_space = 0; + int trailing_break = 0; + int break_space = 0; + int space_break = 0; + + int preceeded_by_whitespace = 0; + int followed_by_whitespace = 0; + int previous_space = 0; + int previous_break = 0; + + STRING_ASSIGN(string, value, length); + + emitter->scalar_data.value = value; + emitter->scalar_data.length = length; + + if (string.start == string.end) + { + emitter->scalar_data.multiline = 0; + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 1; + emitter->scalar_data.single_quoted_allowed = 1; + emitter->scalar_data.block_allowed = 0; + + return 1; + } + + if ((CHECK_AT(string, '-', 0) + && CHECK_AT(string, '-', 1) + && CHECK_AT(string, '-', 2)) + || (CHECK_AT(string, '.', 0) + && CHECK_AT(string, '.', 1) + && CHECK_AT(string, '.', 2))) { + block_indicators = 1; + flow_indicators = 1; + } + + preceeded_by_whitespace = 1; + followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); + + while (string.pointer != string.end) + { + if (string.start == string.pointer) + { + if (CHECK(string, '#') || CHECK(string, ',') + || CHECK(string, '[') || CHECK(string, ']') + || CHECK(string, '{') || CHECK(string, '}') + || CHECK(string, '&') || CHECK(string, '*') + || CHECK(string, '!') || CHECK(string, '|') + || CHECK(string, '>') || CHECK(string, '\'') + || CHECK(string, '"') || CHECK(string, '%') + || CHECK(string, '@') || CHECK(string, '`')) { + flow_indicators = 1; + block_indicators = 1; + } + + if (CHECK(string, '?') || CHECK(string, ':')) { + flow_indicators = 1; + if (followed_by_whitespace) { + block_indicators = 1; + } + } + + if (CHECK(string, '-') && followed_by_whitespace) { + flow_indicators = 1; + block_indicators = 1; + } + } + else + { + if (CHECK(string, ',') || CHECK(string, '?') + || CHECK(string, '[') || CHECK(string, ']') + || CHECK(string, '{') || CHECK(string, '}')) { + flow_indicators = 1; + } + + if (CHECK(string, ':')) { + flow_indicators = 1; + if (followed_by_whitespace) { + block_indicators = 1; + } + } + + if (CHECK(string, '#') && preceeded_by_whitespace) { + flow_indicators = 1; + block_indicators = 1; + } + } + + if (!IS_PRINTABLE(string) + || (!IS_ASCII(string) && !emitter->unicode)) { + special_characters = 1; + } + + if (IS_BREAK(string)) { + line_breaks = 1; + } + + if (IS_SPACE(string)) + { + if (string.start == string.pointer) { + leading_space = 1; + } + if (string.pointer+WIDTH(string) == string.end) { + trailing_space = 1; + } + if (previous_break) { + break_space = 1; + } + previous_space = 1; + previous_break = 0; + } + else if (IS_BREAK(string)) + { + if (string.start == string.pointer) { + leading_break = 1; + } + if (string.pointer+WIDTH(string) == string.end) { + trailing_break = 1; + } + if (previous_space) { + space_break = 1; + } + previous_space = 0; + previous_break = 1; + } + else + { + previous_space = 0; + previous_break = 0; + } + + preceeded_by_whitespace = IS_BLANKZ(string); + MOVE(string); + if (string.pointer != string.end) { + followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); + } + } + + emitter->scalar_data.multiline = line_breaks; + + emitter->scalar_data.flow_plain_allowed = 1; + emitter->scalar_data.block_plain_allowed = 1; + emitter->scalar_data.single_quoted_allowed = 1; + emitter->scalar_data.block_allowed = 1; + + if (leading_space || leading_break || trailing_space || trailing_break) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + } + + if (trailing_space) { + emitter->scalar_data.block_allowed = 0; + } + + if (break_space) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + emitter->scalar_data.single_quoted_allowed = 0; + } + + if (space_break || special_characters) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + emitter->scalar_data.single_quoted_allowed = 0; + emitter->scalar_data.block_allowed = 0; + } + + if (line_breaks) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + } + + if (flow_indicators) { + emitter->scalar_data.flow_plain_allowed = 0; + } + + if (block_indicators) { + emitter->scalar_data.block_plain_allowed = 0; + } + + return 1; +} + +/* + * Check if the event data is valid. + */ + +static int +yaml_emitter_analyze_event(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + emitter->anchor_data.anchor = NULL; + emitter->anchor_data.anchor_length = 0; + emitter->tag_data.handle = NULL; + emitter->tag_data.handle_length = 0; + emitter->tag_data.suffix = NULL; + emitter->tag_data.suffix_length = 0; + emitter->scalar_data.value = NULL; + emitter->scalar_data.length = 0; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + if (!yaml_emitter_analyze_anchor(emitter, + event->data.alias.anchor, 1)) + return 0; + return 1; + + case YAML_SCALAR_EVENT: + if (event->data.scalar.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.scalar.anchor, 0)) + return 0; + } + if (event->data.scalar.tag && (emitter->canonical || + (!event->data.scalar.plain_implicit + && !event->data.scalar.quoted_implicit))) { + if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag)) + return 0; + } + if (!yaml_emitter_analyze_scalar(emitter, + event->data.scalar.value, event->data.scalar.length)) + return 0; + return 1; + + case YAML_SEQUENCE_START_EVENT: + if (event->data.sequence_start.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.sequence_start.anchor, 0)) + return 0; + } + if (event->data.sequence_start.tag && (emitter->canonical || + !event->data.sequence_start.implicit)) { + if (!yaml_emitter_analyze_tag(emitter, + event->data.sequence_start.tag)) + return 0; + } + return 1; + + case YAML_MAPPING_START_EVENT: + if (event->data.mapping_start.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.mapping_start.anchor, 0)) + return 0; + } + if (event->data.mapping_start.tag && (emitter->canonical || + !event->data.mapping_start.implicit)) { + if (!yaml_emitter_analyze_tag(emitter, + event->data.mapping_start.tag)) + return 0; + } + return 1; + + default: + return 1; + } +} + +/* + * Write the BOM character. + */ + +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter) +{ + if (!FLUSH(emitter)) return 0; + + *(emitter->buffer.pointer++) = (yaml_char_t) '\xEF'; + *(emitter->buffer.pointer++) = (yaml_char_t) '\xBB'; + *(emitter->buffer.pointer++) = (yaml_char_t) '\xBF'; + + return 1; +} + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter) +{ + int indent = (emitter->indent >= 0) ? emitter->indent : 0; + + if (!emitter->indention || emitter->column > indent + || (emitter->column == indent && !emitter->whitespace)) { + if (!PUT_BREAK(emitter)) return 0; + } + + while (emitter->column < indent) { + if (!PUT(emitter, ' ')) return 0; + } + + emitter->whitespace = 1; + emitter->indention = 1; + + return 1; +} + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + char *indicator, int need_whitespace, + int is_whitespace, int is_indention) +{ + size_t indicator_length; + yaml_string_t string; + + indicator_length = strlen(indicator); + STRING_ASSIGN(string, (yaml_char_t *)indicator, indicator_length); + + if (need_whitespace && !emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = is_whitespace; + emitter->indention = (emitter->indention && is_indention); + emitter->open_ended = 0; + + return 1; +} + +static int +yaml_emitter_write_anchor(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + if (!emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_tag_content(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, + int need_whitespace) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + if (need_whitespace && !emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (IS_ALPHA(string) + || CHECK(string, ';') || CHECK(string, '/') + || CHECK(string, '?') || CHECK(string, ':') + || CHECK(string, '@') || CHECK(string, '&') + || CHECK(string, '=') || CHECK(string, '+') + || CHECK(string, '$') || CHECK(string, ',') + || CHECK(string, '_') || CHECK(string, '.') + || CHECK(string, '~') || CHECK(string, '*') + || CHECK(string, '\'') || CHECK(string, '(') + || CHECK(string, ')') || CHECK(string, '[') + || CHECK(string, ']')) { + if (!WRITE(emitter, string)) return 0; + } + else { + int width = WIDTH(string); + unsigned int value; + while (width --) { + value = *(string.pointer++); + if (!PUT(emitter, '%')) return 0; + if (!PUT(emitter, (value >> 4) + + ((value >> 4) < 10 ? '0' : 'A' - 10))) + return 0; + if (!PUT(emitter, (value & 0x0F) + + ((value & 0x0F) < 10 ? '0' : 'A' - 10))) + return 0; + } + } + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + int breaks = 0; + + STRING_ASSIGN(string, value, length); + + if (!emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) + { + if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && !IS_SPACE_AT(string, 1)) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else if (IS_BREAK(string)) + { + if (!breaks && CHECK(string, '\n')) { + if (!PUT_BREAK(emitter)) return 0; + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + spaces = 0; + breaks = 0; + } + } + + emitter->whitespace = 0; + emitter->indention = 0; + if (emitter->root_context) + { + emitter->open_ended = 1; + } + + return 1; +} + +static int +yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + int breaks = 0; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "'", 1, 0, 0)) + return 0; + + while (string.pointer != string.end) + { + if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && string.pointer != string.start + && string.pointer != string.end - 1 + && !IS_SPACE_AT(string, 1)) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else if (IS_BREAK(string)) + { + if (!breaks && CHECK(string, '\n')) { + if (!PUT_BREAK(emitter)) return 0; + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (CHECK(string, '\'')) { + if (!PUT(emitter, '\'')) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + spaces = 0; + breaks = 0; + } + } + + if (!yaml_emitter_write_indicator(emitter, "'", 0, 0, 0)) + return 0; + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "\"", 1, 0, 0)) + return 0; + + while (string.pointer != string.end) + { + if (!IS_PRINTABLE(string) || (!emitter->unicode && !IS_ASCII(string)) + || IS_BOM(string) || IS_BREAK(string) + || CHECK(string, '"') || CHECK(string, '\\')) + { + unsigned char octet; + unsigned int width; + unsigned int value; + int k; + + octet = string.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + for (k = 1; k < (int)width; k ++) { + octet = string.pointer[k]; + value = (value << 6) + (octet & 0x3F); + } + string.pointer += width; + + if (!PUT(emitter, '\\')) return 0; + + switch (value) + { + case 0x00: + if (!PUT(emitter, '0')) return 0; + break; + + case 0x07: + if (!PUT(emitter, 'a')) return 0; + break; + + case 0x08: + if (!PUT(emitter, 'b')) return 0; + break; + + case 0x09: + if (!PUT(emitter, 't')) return 0; + break; + + case 0x0A: + if (!PUT(emitter, 'n')) return 0; + break; + + case 0x0B: + if (!PUT(emitter, 'v')) return 0; + break; + + case 0x0C: + if (!PUT(emitter, 'f')) return 0; + break; + + case 0x0D: + if (!PUT(emitter, 'r')) return 0; + break; + + case 0x1B: + if (!PUT(emitter, 'e')) return 0; + break; + + case 0x22: + if (!PUT(emitter, '\"')) return 0; + break; + + case 0x5C: + if (!PUT(emitter, '\\')) return 0; + break; + + case 0x85: + if (!PUT(emitter, 'N')) return 0; + break; + + case 0xA0: + if (!PUT(emitter, '_')) return 0; + break; + + case 0x2028: + if (!PUT(emitter, 'L')) return 0; + break; + + case 0x2029: + if (!PUT(emitter, 'P')) return 0; + break; + + default: + if (value <= 0xFF) { + if (!PUT(emitter, 'x')) return 0; + width = 2; + } + else if (value <= 0xFFFF) { + if (!PUT(emitter, 'u')) return 0; + width = 4; + } + else { + if (!PUT(emitter, 'U')) return 0; + width = 8; + } + for (k = (width-1)*4; k >= 0; k -= 4) { + int digit = (value >> k) & 0x0F; + if (!PUT(emitter, digit + (digit < 10 ? '0' : 'A'-10))) + return 0; + } + } + spaces = 0; + } + else if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && string.pointer != string.start + && string.pointer != string.end - 1) { + if (!yaml_emitter_write_indent(emitter)) return 0; + if (IS_SPACE_AT(string, 1)) { + if (!PUT(emitter, '\\')) return 0; + } + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else + { + if (!WRITE(emitter, string)) return 0; + spaces = 0; + } + } + + if (!yaml_emitter_write_indicator(emitter, "\"", 0, 0, 0)) + return 0; + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, + yaml_string_t string) +{ + char indent_hint[2]; + char *chomp_hint = NULL; + + if (IS_SPACE(string) || IS_BREAK(string)) + { + indent_hint[0] = '0' + (char)emitter->best_indent; + indent_hint[1] = '\0'; + if (!yaml_emitter_write_indicator(emitter, indent_hint, 0, 0, 0)) + return 0; + } + + emitter->open_ended = 0; + + string.pointer = string.end; + if (string.start == string.pointer) + { + chomp_hint = "-"; + } + else + { + do { + string.pointer --; + } while ((*string.pointer & 0xC0) == 0x80); + if (!IS_BREAK(string)) + { + chomp_hint = "-"; + } + else if (string.start == string.pointer) + { + chomp_hint = "+"; + emitter->open_ended = 1; + } + else + { + do { + string.pointer --; + } while ((*string.pointer & 0xC0) == 0x80); + if (IS_BREAK(string)) + { + chomp_hint = "+"; + emitter->open_ended = 1; + } + } + } + + if (chomp_hint) + { + if (!yaml_emitter_write_indicator(emitter, chomp_hint, 0, 0, 0)) + return 0; + } + + return 1; +} + +static int +yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + int breaks = 1; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "|", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_block_scalar_hints(emitter, string)) + return 0; + if (!PUT_BREAK(emitter)) return 0; + emitter->indention = 1; + emitter->whitespace = 1; + + while (string.pointer != string.end) + { + if (IS_BREAK(string)) + { + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + breaks = 0; + } + } + + return 1; +} + +static int +yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + int breaks = 1; + int leading_spaces = 1; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, ">", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_block_scalar_hints(emitter, string)) + return 0; + if (!PUT_BREAK(emitter)) return 0; + emitter->indention = 1; + emitter->whitespace = 1; + + while (string.pointer != string.end) + { + if (IS_BREAK(string)) + { + if (!breaks && !leading_spaces && CHECK(string, '\n')) { + int k = 0; + while (IS_BREAK_AT(string, k)) { + k += WIDTH_AT(string, k); + } + if (!IS_BLANKZ_AT(string, k)) { + if (!PUT_BREAK(emitter)) return 0; + } + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + leading_spaces = IS_BLANK(string); + } + if (!breaks && IS_SPACE(string) && !IS_SPACE_AT(string, 1) + && emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + emitter->indention = 0; + breaks = 0; + } + } + + return 1; +} + diff --git a/libyaml/src/loader.c b/libyaml/src/loader.c new file mode 100644 index 00000000..871149ab --- /dev/null +++ b/libyaml/src/loader.c @@ -0,0 +1,444 @@ + +#include "yaml_private.h" + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); + +/* + * Error handling. + */ + +static int +yaml_parser_set_composer_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark); + +static int +yaml_parser_set_composer_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark); + + +/* + * Alias handling. + */ + +static int +yaml_parser_register_anchor(yaml_parser_t *parser, + int index, yaml_char_t *anchor); + +/* + * Clean up functions. + */ + +static void +yaml_parser_delete_aliases(yaml_parser_t *parser); + +/* + * Composer functions. + */ + +static int +yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event); + +/* + * Load the next document of the stream. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document) +{ + yaml_event_t event; + + assert(parser); /* Non-NULL parser object is expected. */ + assert(document); /* Non-NULL document object is expected. */ + + memset(document, 0, sizeof(yaml_document_t)); + if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE)) + goto error; + + if (!parser->stream_start_produced) { + if (!yaml_parser_parse(parser, &event)) goto error; + assert(event.type == YAML_STREAM_START_EVENT); + /* STREAM-START is expected. */ + } + + if (parser->stream_end_produced) { + return 1; + } + + if (!yaml_parser_parse(parser, &event)) goto error; + if (event.type == YAML_STREAM_END_EVENT) { + return 1; + } + + if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE)) + goto error; + + parser->document = document; + + if (!yaml_parser_load_document(parser, &event)) goto error; + + yaml_parser_delete_aliases(parser); + parser->document = NULL; + + return 1; + +error: + + yaml_parser_delete_aliases(parser); + yaml_document_delete(document); + parser->document = NULL; + + return 0; +} + +/* + * Set composer error. + */ + +static int +yaml_parser_set_composer_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_COMPOSER_ERROR; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +/* + * Set composer error with context. + */ + +static int +yaml_parser_set_composer_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_COMPOSER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +/* + * Delete the stack of aliases. + */ + +static void +yaml_parser_delete_aliases(yaml_parser_t *parser) +{ + while (!STACK_EMPTY(parser, parser->aliases)) { + yaml_free(POP(parser, parser->aliases).anchor); + } + STACK_DEL(parser, parser->aliases); +} + +/* + * Compose a document object. + */ + +static int +yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_event_t event; + + assert(first_event->type == YAML_DOCUMENT_START_EVENT); + /* DOCUMENT-START is expected. */ + + parser->document->version_directive + = first_event->data.document_start.version_directive; + parser->document->tag_directives.start + = first_event->data.document_start.tag_directives.start; + parser->document->tag_directives.end + = first_event->data.document_start.tag_directives.end; + parser->document->start_implicit + = first_event->data.document_start.implicit; + parser->document->start_mark = first_event->start_mark; + + if (!yaml_parser_parse(parser, &event)) return 0; + + if (!yaml_parser_load_node(parser, &event)) return 0; + + if (!yaml_parser_parse(parser, &event)) return 0; + assert(event.type == YAML_DOCUMENT_END_EVENT); + /* DOCUMENT-END is expected. */ + + parser->document->end_implicit = event.data.document_end.implicit; + parser->document->end_mark = event.end_mark; + + return 1; +} + +/* + * Compose a node. + */ + +static int +yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event) +{ + switch (first_event->type) { + case YAML_ALIAS_EVENT: + return yaml_parser_load_alias(parser, first_event); + case YAML_SCALAR_EVENT: + return yaml_parser_load_scalar(parser, first_event); + case YAML_SEQUENCE_START_EVENT: + return yaml_parser_load_sequence(parser, first_event); + case YAML_MAPPING_START_EVENT: + return yaml_parser_load_mapping(parser, first_event); + default: + assert(0); /* Could not happen. */ + return 0; + } + + return 0; +} + +/* + * Add an anchor. + */ + +static int +yaml_parser_register_anchor(yaml_parser_t *parser, + int index, yaml_char_t *anchor) +{ + yaml_alias_data_t data; + yaml_alias_data_t *alias_data; + + if (!anchor) return 1; + + data.anchor = anchor; + data.index = index; + data.mark = parser->document->nodes.start[index-1].start_mark; + + for (alias_data = parser->aliases.start; + alias_data != parser->aliases.top; alias_data ++) { + if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { + yaml_free(anchor); + return yaml_parser_set_composer_error_context(parser, + "found duplicate anchor; first occurence", + alias_data->mark, "second occurence", data.mark); + } + } + + if (!PUSH(parser, parser->aliases, data)) { + yaml_free(anchor); + return 0; + } + + return 1; +} + +/* + * Compose a node corresponding to an alias. + */ + +static int +yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_char_t *anchor = first_event->data.alias.anchor; + yaml_alias_data_t *alias_data; + + for (alias_data = parser->aliases.start; + alias_data != parser->aliases.top; alias_data ++) { + if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { + yaml_free(anchor); + return alias_data->index; + } + } + + yaml_free(anchor); + return yaml_parser_set_composer_error(parser, "found undefined alias", + first_event->start_mark); +} + +/* + * Compose a scalar node. + */ + +static int +yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_node_t node; + int index; + yaml_char_t *tag = first_event->data.scalar.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG); + if (!tag) goto error; + } + + SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value, + first_event->data.scalar.length, first_event->data.scalar.style, + first_event->start_mark, first_event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + first_event->data.scalar.anchor)) return 0; + + return index; + +error: + yaml_free(tag); + yaml_free(first_event->data.scalar.anchor); + yaml_free(first_event->data.scalar.value); + return 0; +} + +/* + * Compose a sequence node. + */ + +static int +yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_event_t event; + yaml_node_t node; + struct { + yaml_node_item_t *start; + yaml_node_item_t *end; + yaml_node_item_t *top; + } items = { NULL, NULL, NULL }; + int index, item_index; + yaml_char_t *tag = first_event->data.sequence_start.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG); + if (!tag) goto error; + } + + if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error; + + SEQUENCE_NODE_INIT(node, tag, items.start, items.end, + first_event->data.sequence_start.style, + first_event->start_mark, first_event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + first_event->data.sequence_start.anchor)) return 0; + + if (!yaml_parser_parse(parser, &event)) return 0; + + while (event.type != YAML_SEQUENCE_END_EVENT) { + if (!STACK_LIMIT(parser, + parser->document->nodes.start[index-1].data.sequence.items, + INT_MAX-1)) return 0; + item_index = yaml_parser_load_node(parser, &event); + if (!item_index) return 0; + if (!PUSH(parser, + parser->document->nodes.start[index-1].data.sequence.items, + item_index)) return 0; + if (!yaml_parser_parse(parser, &event)) return 0; + } + + parser->document->nodes.start[index-1].end_mark = event.end_mark; + + return index; + +error: + yaml_free(tag); + yaml_free(first_event->data.sequence_start.anchor); + return 0; +} + +/* + * Compose a mapping node. + */ + +static int +yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_event_t event; + yaml_node_t node; + struct { + yaml_node_pair_t *start; + yaml_node_pair_t *end; + yaml_node_pair_t *top; + } pairs = { NULL, NULL, NULL }; + int index; + yaml_node_pair_t pair; + yaml_char_t *tag = first_event->data.mapping_start.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG); + if (!tag) goto error; + } + + if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error; + + MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end, + first_event->data.mapping_start.style, + first_event->start_mark, first_event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + first_event->data.mapping_start.anchor)) return 0; + + if (!yaml_parser_parse(parser, &event)) return 0; + + while (event.type != YAML_MAPPING_END_EVENT) { + if (!STACK_LIMIT(parser, + parser->document->nodes.start[index-1].data.mapping.pairs, + INT_MAX-1)) return 0; + pair.key = yaml_parser_load_node(parser, &event); + if (!pair.key) return 0; + if (!yaml_parser_parse(parser, &event)) return 0; + pair.value = yaml_parser_load_node(parser, &event); + if (!pair.value) return 0; + if (!PUSH(parser, + parser->document->nodes.start[index-1].data.mapping.pairs, + pair)) return 0; + if (!yaml_parser_parse(parser, &event)) return 0; + } + + parser->document->nodes.start[index-1].end_mark = event.end_mark; + + return index; + +error: + yaml_free(tag); + yaml_free(first_event->data.mapping_start.anchor); + return 0; +} + diff --git a/libyaml/src/parser.c b/libyaml/src/parser.c new file mode 100644 index 00000000..eb2a2c79 --- /dev/null +++ b/libyaml/src/parser.c @@ -0,0 +1,1374 @@ + +/* + * The parser implements the following grammar: + * + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * block_node_or_indentless_sequence ::= + * ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + */ + +#include "yaml_private.h" + +/* + * Peek the next token in the token queue. + */ + +#define PEEK_TOKEN(parser) \ + ((parser->token_available || yaml_parser_fetch_more_tokens(parser)) ? \ + parser->tokens.head : NULL) + +/* + * Remove the next token from the queue (must be called after PEEK_TOKEN). + */ + +#define SKIP_TOKEN(parser) \ + (parser->token_available = 0, \ + parser->tokens_parsed ++, \ + parser->stream_end_produced = \ + (parser->tokens.head->type == YAML_STREAM_END_TOKEN), \ + parser->tokens.head ++) + +/* + * Public API declarations. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); + +/* + * Error handling. + */ + +static int +yaml_parser_set_parser_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark); + +static int +yaml_parser_set_parser_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark); + +/* + * State functions. + */ + +static int +yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, + int implicit); + +static int +yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, + int block, int indentless_sequence); + +static int +yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, + yaml_event_t *event, int empty); + +/* + * Utility functions. + */ + +static int +yaml_parser_process_empty_scalar(yaml_parser_t *parser, + yaml_event_t *event, yaml_mark_t mark); + +static int +yaml_parser_process_directives(yaml_parser_t *parser, + yaml_version_directive_t **version_directive_ref, + yaml_tag_directive_t **tag_directives_start_ref, + yaml_tag_directive_t **tag_directives_end_ref); + +static int +yaml_parser_append_tag_directive(yaml_parser_t *parser, + yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark); + +/* + * Get the next event. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event) +{ + assert(parser); /* Non-NULL parser object is expected. */ + assert(event); /* Non-NULL event object is expected. */ + + /* Erase the event object. */ + + memset(event, 0, sizeof(yaml_event_t)); + + /* No events after the end of the stream or error. */ + + if (parser->stream_end_produced || parser->error || + parser->state == YAML_PARSE_END_STATE) { + return 1; + } + + /* Generate the next event. */ + + return yaml_parser_state_machine(parser, event); +} + +/* + * Set parser error. + */ + +static int +yaml_parser_set_parser_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_PARSER_ERROR; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +static int +yaml_parser_set_parser_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_PARSER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + + +/* + * State dispatcher. + */ + +static int +yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event) +{ + switch (parser->state) + { + case YAML_PARSE_STREAM_START_STATE: + return yaml_parser_parse_stream_start(parser, event); + + case YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, 1); + + case YAML_PARSE_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, 0); + + case YAML_PARSE_DOCUMENT_CONTENT_STATE: + return yaml_parser_parse_document_content(parser, event); + + case YAML_PARSE_DOCUMENT_END_STATE: + return yaml_parser_parse_document_end(parser, event); + + case YAML_PARSE_BLOCK_NODE_STATE: + return yaml_parser_parse_node(parser, event, 1, 0); + + case YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return yaml_parser_parse_node(parser, event, 1, 1); + + case YAML_PARSE_FLOW_NODE_STATE: + return yaml_parser_parse_node(parser, event, 0, 0); + + case YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, 1); + + case YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, 0); + + case YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_indentless_sequence_entry(parser, event); + + case YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, 1); + + case YAML_PARSE_BLOCK_MAPPING_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, 0); + + case YAML_PARSE_BLOCK_MAPPING_VALUE_STATE: + return yaml_parser_parse_block_mapping_value(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, 1); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, 0); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event); + + case YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, 1); + + case YAML_PARSE_FLOW_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, 0); + + case YAML_PARSE_FLOW_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, 0); + + case YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, 1); + + default: + assert(1); /* Invalid state. */ + } + + return 0; +} + +/* + * Parse the production: + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * ************ + */ + +static int +yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_STREAM_START_TOKEN) { + return yaml_parser_set_parser_error(parser, + "did not find expected ", token->start_mark); + } + + parser->state = YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE; + STREAM_START_EVENT_INIT(*event, token->data.stream_start.encoding, + token->start_mark, token->start_mark); + SKIP_TOKEN(parser); + + return 1; +} + +/* + * Parse the productions: + * implicit_document ::= block_node DOCUMENT-END* + * * + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * ************************* + */ + +static int +yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, + int implicit) +{ + yaml_token_t *token; + yaml_version_directive_t *version_directive = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + } tag_directives = { NULL, NULL }; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + /* Parse extra document end indicators. */ + + if (!implicit) + { + while (token->type == YAML_DOCUMENT_END_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + } + + /* Parse an implicit document. */ + + if (implicit && token->type != YAML_VERSION_DIRECTIVE_TOKEN && + token->type != YAML_TAG_DIRECTIVE_TOKEN && + token->type != YAML_DOCUMENT_START_TOKEN && + token->type != YAML_STREAM_END_TOKEN) + { + if (!yaml_parser_process_directives(parser, NULL, NULL, NULL)) + return 0; + if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) + return 0; + parser->state = YAML_PARSE_BLOCK_NODE_STATE; + DOCUMENT_START_EVENT_INIT(*event, NULL, NULL, NULL, 1, + token->start_mark, token->start_mark); + return 1; + } + + /* Parse an explicit document. */ + + else if (token->type != YAML_STREAM_END_TOKEN) + { + yaml_mark_t start_mark, end_mark; + start_mark = token->start_mark; + if (!yaml_parser_process_directives(parser, &version_directive, + &tag_directives.start, &tag_directives.end)) + return 0; + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type != YAML_DOCUMENT_START_TOKEN) { + yaml_parser_set_parser_error(parser, + "did not find expected ", token->start_mark); + goto error; + } + if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) + goto error; + parser->state = YAML_PARSE_DOCUMENT_CONTENT_STATE; + end_mark = token->end_mark; + DOCUMENT_START_EVENT_INIT(*event, version_directive, + tag_directives.start, tag_directives.end, 0, + start_mark, end_mark); + SKIP_TOKEN(parser); + version_directive = NULL; + tag_directives.start = tag_directives.end = NULL; + return 1; + } + + /* Parse the stream end. */ + + else + { + parser->state = YAML_PARSE_END_STATE; + STREAM_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + +error: + yaml_free(version_directive); + while (tag_directives.start != tag_directives.end) { + yaml_free(tag_directives.end[-1].handle); + yaml_free(tag_directives.end[-1].prefix); + tag_directives.end --; + } + yaml_free(tag_directives.start); + return 0; +} + +/* + * Parse the productions: + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * *********** + */ + +static int +yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VERSION_DIRECTIVE_TOKEN || + token->type == YAML_TAG_DIRECTIVE_TOKEN || + token->type == YAML_DOCUMENT_START_TOKEN || + token->type == YAML_DOCUMENT_END_TOKEN || + token->type == YAML_STREAM_END_TOKEN) { + parser->state = POP(parser, parser->states); + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + else { + return yaml_parser_parse_node(parser, event, 1, 0); + } +} + +/* + * Parse the productions: + * implicit_document ::= block_node DOCUMENT-END* + * ************* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * ************* + */ + +static int +yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + yaml_mark_t start_mark, end_mark; + int implicit = 1; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + start_mark = end_mark = token->start_mark; + + if (token->type == YAML_DOCUMENT_END_TOKEN) { + end_mark = token->end_mark; + SKIP_TOKEN(parser); + implicit = 0; + } + + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + parser->state = YAML_PARSE_DOCUMENT_START_STATE; + DOCUMENT_END_EVENT_INIT(*event, implicit, start_mark, end_mark); + + return 1; +} + +/* + * Parse the productions: + * block_node_or_indentless_sequence ::= + * ALIAS + * ***** + * | properties (block_content | indentless_block_sequence)? + * ********** * + * | block_content | indentless_block_sequence + * * + * block_node ::= ALIAS + * ***** + * | properties block_content? + * ********** * + * | block_content + * * + * flow_node ::= ALIAS + * ***** + * | properties flow_content? + * ********** * + * | flow_content + * * + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * ************************* + * block_content ::= block_collection | flow_collection | SCALAR + * ****** + * flow_content ::= flow_collection | SCALAR + * ****** + */ + +static int +yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, + int block, int indentless_sequence) +{ + yaml_token_t *token; + yaml_char_t *anchor = NULL; + yaml_char_t *tag_handle = NULL; + yaml_char_t *tag_suffix = NULL; + yaml_char_t *tag = NULL; + yaml_mark_t start_mark, end_mark, tag_mark; + int implicit; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_ALIAS_TOKEN) + { + parser->state = POP(parser, parser->states); + ALIAS_EVENT_INIT(*event, token->data.alias.value, + token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + start_mark = end_mark = token->start_mark; + + if (token->type == YAML_ANCHOR_TOKEN) + { + anchor = token->data.anchor.value; + start_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type == YAML_TAG_TOKEN) + { + tag_handle = token->data.tag.handle; + tag_suffix = token->data.tag.suffix; + tag_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + } + else if (token->type == YAML_TAG_TOKEN) + { + tag_handle = token->data.tag.handle; + tag_suffix = token->data.tag.suffix; + start_mark = tag_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type == YAML_ANCHOR_TOKEN) + { + anchor = token->data.anchor.value; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + } + + if (tag_handle) { + if (!*tag_handle) { + tag = tag_suffix; + yaml_free(tag_handle); + tag_handle = tag_suffix = NULL; + } + else { + yaml_tag_directive_t *tag_directive; + for (tag_directive = parser->tag_directives.start; + tag_directive != parser->tag_directives.top; + tag_directive ++) { + if (strcmp((char *)tag_directive->handle, (char *)tag_handle) == 0) { + size_t prefix_len = strlen((char *)tag_directive->prefix); + size_t suffix_len = strlen((char *)tag_suffix); + tag = yaml_malloc(prefix_len+suffix_len+1); + if (!tag) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + memcpy(tag, tag_directive->prefix, prefix_len); + memcpy(tag+prefix_len, tag_suffix, suffix_len); + tag[prefix_len+suffix_len] = '\0'; + yaml_free(tag_handle); + yaml_free(tag_suffix); + tag_handle = tag_suffix = NULL; + break; + } + } + if (!tag) { + yaml_parser_set_parser_error_context(parser, + "while parsing a node", start_mark, + "found undefined tag handle", tag_mark); + goto error; + } + } + } + + implicit = (!tag || !*tag); + if (indentless_sequence && token->type == YAML_BLOCK_ENTRY_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else { + if (token->type == YAML_SCALAR_TOKEN) { + int plain_implicit = 0; + int quoted_implicit = 0; + end_mark = token->end_mark; + if ((token->data.scalar.style == YAML_PLAIN_SCALAR_STYLE && !tag) + || (tag && strcmp((char *)tag, "!") == 0)) { + plain_implicit = 1; + } + else if (!tag) { + quoted_implicit = 1; + } + parser->state = POP(parser, parser->states); + SCALAR_EVENT_INIT(*event, anchor, tag, + token->data.scalar.value, token->data.scalar.length, + plain_implicit, quoted_implicit, + token->data.scalar.style, start_mark, end_mark); + SKIP_TOKEN(parser); + return 1; + } + else if (token->type == YAML_FLOW_SEQUENCE_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_FLOW_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else if (token->type == YAML_FLOW_MAPPING_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_FLOW_MAPPING_STYLE, start_mark, end_mark); + return 1; + } + else if (block && token->type == YAML_BLOCK_SEQUENCE_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else if (block && token->type == YAML_BLOCK_MAPPING_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_MAPPING_STYLE, start_mark, end_mark); + return 1; + } + else if (anchor || tag) { + yaml_char_t *value = yaml_malloc(1); + if (!value) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + value[0] = '\0'; + parser->state = POP(parser, parser->states); + SCALAR_EVENT_INIT(*event, anchor, tag, value, 0, + implicit, 0, YAML_PLAIN_SCALAR_STYLE, + start_mark, end_mark); + return 1; + } + else { + yaml_parser_set_parser_error_context(parser, + (block ? "while parsing a block node" + : "while parsing a flow node"), start_mark, + "did not find expected node content", token->start_mark); + goto error; + } + } + } + +error: + yaml_free(anchor); + yaml_free(tag_handle); + yaml_free(tag_suffix); + yaml_free(tag); + + return 0; +} + +/* + * Parse the productions: + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * ******************** *********** * ********* + */ + +static int +yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_BLOCK_ENTRY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_BLOCK_ENTRY_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 0); + } + else { + parser->state = YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else if (token->type == YAML_BLOCK_END_TOKEN) + { + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + return yaml_parser_set_parser_error_context(parser, + "while parsing a block collection", POP(parser, parser->marks), + "did not find expected '-' indicator", token->start_mark); + } +} + +/* + * Parse the productions: + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * *********** * + */ + +static int +yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_BLOCK_ENTRY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_BLOCK_ENTRY_TOKEN && + token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 0); + } + else { + parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else + { + parser->state = POP(parser, parser->states); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->start_mark); + return 1; + } +} + +/* + * Parse the productions: + * block_mapping ::= BLOCK-MAPPING_START + * ******************* + * ((KEY block_node_or_indentless_sequence?)? + * *** * + * (VALUE block_node_or_indentless_sequence?)?)* + * + * BLOCK-END + * ********* + */ + +static int +yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_KEY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 1); + } + else { + parser->state = YAML_PARSE_BLOCK_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else if (token->type == YAML_BLOCK_END_TOKEN) + { + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + return yaml_parser_set_parser_error_context(parser, + "while parsing a block mapping", POP(parser, parser->marks), + "did not find expected key", token->start_mark); + } +} + +/* + * Parse the productions: + * block_mapping ::= BLOCK-MAPPING_START + * + * ((KEY block_node_or_indentless_sequence?)? + * + * (VALUE block_node_or_indentless_sequence?)?)* + * ***** * + * BLOCK-END + * + */ + +static int +yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VALUE_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_MAPPING_KEY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 1); + } + else { + parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else + { + parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); + } +} + +/* + * Parse the productions: + * flow_sequence ::= FLOW-SEQUENCE-START + * ******************* + * (flow_sequence_entry FLOW-ENTRY)* + * * ********** + * flow_sequence_entry? + * * + * FLOW-SEQUENCE-END + * ***************** + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * + */ + +static int +yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) + { + if (!first) { + if (token->type == YAML_FLOW_ENTRY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + else { + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow sequence", POP(parser, parser->marks), + "did not find expected ',' or ']'", token->start_mark); + } + } + + if (token->type == YAML_KEY_TOKEN) { + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, NULL, NULL, + 1, YAML_FLOW_MAPPING_STYLE, + token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * *** * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_VALUE_TOKEN && token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + else { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * ***** * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VALUE_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE; + + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->start_mark); + return 1; +} + +/* + * Parse the productions: + * flow_mapping ::= FLOW-MAPPING-START + * ****************** + * (flow_mapping_entry FLOW-ENTRY)* + * * ********** + * flow_mapping_entry? + * ****************** + * FLOW-MAPPING-END + * **************** + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * *** * + */ + +static int +yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_FLOW_MAPPING_END_TOKEN) + { + if (!first) { + if (token->type == YAML_FLOW_ENTRY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + else { + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow mapping", POP(parser, parser->marks), + "did not find expected ',' or '}'", token->start_mark); + } + } + + if (token->type == YAML_KEY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_VALUE_TOKEN + && token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + else { + parser->state = YAML_PARSE_FLOW_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + } + else if (token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; +} + +/* + * Parse the productions: + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * ***** * + */ + +static int +yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, + yaml_event_t *event, int empty) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (empty) { + parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + + if (token->type == YAML_VALUE_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); +} + +/* + * Generate an empty scalar event. + */ + +static int +yaml_parser_process_empty_scalar(yaml_parser_t *parser, yaml_event_t *event, + yaml_mark_t mark) +{ + yaml_char_t *value; + + value = yaml_malloc(1); + if (!value) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + value[0] = '\0'; + + SCALAR_EVENT_INIT(*event, NULL, NULL, value, 0, + 1, 0, YAML_PLAIN_SCALAR_STYLE, mark, mark); + + return 1; +} + +/* + * Parse directives. + */ + +static int +yaml_parser_process_directives(yaml_parser_t *parser, + yaml_version_directive_t **version_directive_ref, + yaml_tag_directive_t **tag_directives_start_ref, + yaml_tag_directive_t **tag_directives_end_ref) +{ + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *default_tag_directive; + yaml_version_directive_t *version_directive = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives = { NULL, NULL, NULL }; + yaml_token_t *token; + + if (!STACK_INIT(parser, tag_directives, INITIAL_STACK_SIZE)) + goto error; + + token = PEEK_TOKEN(parser); + if (!token) goto error; + + while (token->type == YAML_VERSION_DIRECTIVE_TOKEN || + token->type == YAML_TAG_DIRECTIVE_TOKEN) + { + if (token->type == YAML_VERSION_DIRECTIVE_TOKEN) { + if (version_directive) { + yaml_parser_set_parser_error(parser, + "found duplicate %YAML directive", token->start_mark); + goto error; + } + if (token->data.version_directive.major != 1 + || token->data.version_directive.minor != 1) { + yaml_parser_set_parser_error(parser, + "found incompatible YAML document", token->start_mark); + goto error; + } + version_directive = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + version_directive->major = token->data.version_directive.major; + version_directive->minor = token->data.version_directive.minor; + } + + else if (token->type == YAML_TAG_DIRECTIVE_TOKEN) { + yaml_tag_directive_t value; + value.handle = token->data.tag_directive.handle; + value.prefix = token->data.tag_directive.prefix; + + if (!yaml_parser_append_tag_directive(parser, value, 0, + token->start_mark)) + goto error; + if (!PUSH(parser, tag_directives, value)) + goto error; + } + + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + + for (default_tag_directive = default_tag_directives; + default_tag_directive->handle; default_tag_directive++) { + if (!yaml_parser_append_tag_directive(parser, *default_tag_directive, 1, + token->start_mark)) + goto error; + } + + if (version_directive_ref) { + *version_directive_ref = version_directive; + } + if (tag_directives_start_ref) { + if (STACK_EMPTY(parser, tag_directives)) { + *tag_directives_start_ref = *tag_directives_end_ref = NULL; + STACK_DEL(parser, tag_directives); + } + else { + *tag_directives_start_ref = tag_directives.start; + *tag_directives_end_ref = tag_directives.top; + } + } + else { + STACK_DEL(parser, tag_directives); + } + + return 1; + +error: + yaml_free(version_directive); + while (!STACK_EMPTY(parser, tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, tag_directives); + return 0; +} + +/* + * Append a tag directive to the directives stack. + */ + +static int +yaml_parser_append_tag_directive(yaml_parser_t *parser, + yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = parser->tag_directives.start; + tag_directive != parser->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_parser_set_parser_error(parser, + "found duplicate %TAG directive", mark); + } + } + + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + + if (!PUSH(parser, parser->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); + return 0; +} + diff --git a/libyaml/src/reader.c b/libyaml/src/reader.c new file mode 100644 index 00000000..d47921ce --- /dev/null +++ b/libyaml/src/reader.c @@ -0,0 +1,469 @@ + +#include "yaml_private.h" + +/* + * Declarations. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value); + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser); + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser); + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Set the reader error and return 0. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value) +{ + parser->error = YAML_READER_ERROR; + parser->problem = problem; + parser->problem_offset = offset; + parser->problem_value = value; + + return 0; +} + +/* + * Byte order marks. + */ + +#define BOM_UTF8 "\xef\xbb\xbf" +#define BOM_UTF16LE "\xff\xfe" +#define BOM_UTF16BE "\xfe\xff" + +/* + * Determine the input stream encoding by checking the BOM symbol. If no BOM is + * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. + */ + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser) +{ + /* Ensure that we had enough bytes in the raw buffer. */ + + while (!parser->eof + && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) { + if (!yaml_parser_update_raw_buffer(parser)) { + return 0; + } + } + + /* Determine the encoding. */ + + if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) { + parser->encoding = YAML_UTF16LE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) { + parser->encoding = YAML_UTF16BE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) { + parser->encoding = YAML_UTF8_ENCODING; + parser->raw_buffer.pointer += 3; + parser->offset += 3; + } + else { + parser->encoding = YAML_UTF8_ENCODING; + } + + return 1; +} + +/* + * Update the raw buffer. + */ + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser) +{ + size_t size_read = 0; + + /* Return if the raw buffer is full. */ + + if (parser->raw_buffer.start == parser->raw_buffer.pointer + && parser->raw_buffer.last == parser->raw_buffer.end) + return 1; + + /* Return on EOF. */ + + if (parser->eof) return 1; + + /* Move the remaining bytes in the raw buffer to the beginning. */ + + if (parser->raw_buffer.start < parser->raw_buffer.pointer + && parser->raw_buffer.pointer < parser->raw_buffer.last) { + memmove(parser->raw_buffer.start, parser->raw_buffer.pointer, + parser->raw_buffer.last - parser->raw_buffer.pointer); + } + parser->raw_buffer.last -= + parser->raw_buffer.pointer - parser->raw_buffer.start; + parser->raw_buffer.pointer = parser->raw_buffer.start; + + /* Call the read handler to fill the buffer. */ + + if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last, + parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) { + return yaml_parser_set_reader_error(parser, "input error", + parser->offset, -1); + } + parser->raw_buffer.last += size_read; + if (!size_read) { + parser->eof = 1; + } + + return 1; +} + +/* + * Ensure that the buffer contains at least `length` characters. + * Return 1 on success, 0 on failure. + * + * The length is supposed to be significantly less that the buffer size. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) +{ + int first = 1; + + assert(parser->read_handler); /* Read handler must be set. */ + + /* If the EOF flag is set and the raw buffer is empty, do nothing. */ + + if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last) + return 1; + + /* Return if the buffer contains enough characters. */ + + if (parser->unread >= length) + return 1; + + /* Determine the input encoding if it is not known yet. */ + + if (!parser->encoding) { + if (!yaml_parser_determine_encoding(parser)) + return 0; + } + + /* Move the unread characters to the beginning of the buffer. */ + + if (parser->buffer.start < parser->buffer.pointer + && parser->buffer.pointer < parser->buffer.last) { + size_t size = parser->buffer.last - parser->buffer.pointer; + memmove(parser->buffer.start, parser->buffer.pointer, size); + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start + size; + } + else if (parser->buffer.pointer == parser->buffer.last) { + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start; + } + + /* Fill the buffer until it has enough characters. */ + + while (parser->unread < length) + { + /* Fill the raw buffer if necessary. */ + + if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) { + if (!yaml_parser_update_raw_buffer(parser)) return 0; + } + first = 0; + + /* Decode the raw buffer. */ + + while (parser->raw_buffer.pointer != parser->raw_buffer.last) + { + unsigned int value = 0, value2 = 0; + int incomplete = 0; + unsigned char octet; + unsigned int width = 0; + int low, high; + size_t k; + size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer; + + /* Decode the next character. */ + + switch (parser->encoding) + { + case YAML_UTF8_ENCODING: + + /* + * Decode a UTF-8 character. Check RFC 3629 + * (http://www.ietf.org/rfc/rfc3629.txt) for more details. + * + * The following table (taken from the RFC) is used for + * decoding. + * + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+------------------------------------ + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * Additionally, the characters in the range 0xD800-0xDFFF + * are prohibited as they are reserved for use with UTF-16 + * surrogate pairs. + */ + + /* Determine the length of the UTF-8 sequence. */ + + octet = parser->raw_buffer.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + + /* Check if the leading octet is valid. */ + + if (!width) + return yaml_parser_set_reader_error(parser, + "invalid leading UTF-8 octet", + parser->offset, octet); + + /* Check if the raw buffer contains an incomplete character. */ + + if (width > raw_unread) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-8 octet sequence", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Decode the leading octet. */ + + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + + /* Check and decode the trailing octets. */ + + for (k = 1; k < width; k ++) + { + octet = parser->raw_buffer.pointer[k]; + + /* Check if the octet is valid. */ + + if ((octet & 0xC0) != 0x80) + return yaml_parser_set_reader_error(parser, + "invalid trailing UTF-8 octet", + parser->offset+k, octet); + + /* Decode the octet. */ + + value = (value << 6) + (octet & 0x3F); + } + + /* Check the length of the sequence against the value. */ + + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) + return yaml_parser_set_reader_error(parser, + "invalid length of a UTF-8 sequence", + parser->offset, -1); + + /* Check the range of the value. */ + + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) + return yaml_parser_set_reader_error(parser, + "invalid Unicode character", + parser->offset, value); + + break; + + case YAML_UTF16LE_ENCODING: + case YAML_UTF16BE_ENCODING: + + low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); + high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); + + /* + * The UTF-16 encoding is not as simple as one might + * naively think. Check RFC 2781 + * (http://www.ietf.org/rfc/rfc2781.txt). + * + * Normally, two subsequent bytes describe a Unicode + * character. However a special technique (called a + * surrogate pair) is used for specifying character + * values larger than 0xFFFF. + * + * A surrogate pair consists of two pseudo-characters: + * high surrogate area (0xD800-0xDBFF) + * low surrogate area (0xDC00-0xDFFF) + * + * The following formulas are used for decoding + * and encoding characters using surrogate pairs: + * + * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) + * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) + * W1 = 110110yyyyyyyyyy + * W2 = 110111xxxxxxxxxx + * + * where U is the character value, W1 is the high surrogate + * area, W2 is the low surrogate area. + */ + + /* Check for incomplete UTF-16 character. */ + + if (raw_unread < 2) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 character", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Get the character. */ + + value = parser->raw_buffer.pointer[low] + + (parser->raw_buffer.pointer[high] << 8); + + /* Check for unexpected low surrogate area. */ + + if ((value & 0xFC00) == 0xDC00) + return yaml_parser_set_reader_error(parser, + "unexpected low surrogate area", + parser->offset, value); + + /* Check for a high surrogate area. */ + + if ((value & 0xFC00) == 0xD800) { + + width = 4; + + /* Check for incomplete surrogate pair. */ + + if (raw_unread < 4) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 surrogate pair", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Get the next character. */ + + value2 = parser->raw_buffer.pointer[low+2] + + (parser->raw_buffer.pointer[high+2] << 8); + + /* Check for a low surrogate area. */ + + if ((value2 & 0xFC00) != 0xDC00) + return yaml_parser_set_reader_error(parser, + "expected low surrogate area", + parser->offset+2, value2); + + /* Generate the value of the surrogate pair. */ + + value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF); + } + + else { + width = 2; + } + + break; + + default: + assert(1); /* Impossible. */ + } + + /* Check if the raw buffer contains enough bytes to form a character. */ + + if (incomplete) break; + + /* + * Check if the character is in the allowed range: + * #x9 | #xA | #xD | [#x20-#x7E] (8 bit) + * | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) + * | [#x10000-#x10FFFF] (32 bit) + */ + + if (! (value == 0x09 || value == 0x0A || value == 0x0D + || (value >= 0x20 && value <= 0x7E) + || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF) + || (value >= 0xE000 && value <= 0xFFFD) + || (value >= 0x10000 && value <= 0x10FFFF))) + return yaml_parser_set_reader_error(parser, + "control characters are not allowed", + parser->offset, value); + + /* Move the raw pointers. */ + + parser->raw_buffer.pointer += width; + parser->offset += width; + + /* Finally put the character into the buffer. */ + + /* 0000 0000-0000 007F -> 0xxxxxxx */ + if (value <= 0x7F) { + *(parser->buffer.last++) = value; + } + /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */ + else if (value <= 0x7FF) { + *(parser->buffer.last++) = 0xC0 + (value >> 6); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */ + else if (value <= 0xFFFF) { + *(parser->buffer.last++) = 0xE0 + (value >> 12); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + else { + *(parser->buffer.last++) = 0xF0 + (value >> 18); + *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + + parser->unread ++; + } + + /* On EOF, put NUL into the buffer and return. */ + + if (parser->eof) { + *(parser->buffer.last++) = '\0'; + parser->unread ++; + return 1; + } + + } + + if (parser->offset >= PTRDIFF_MAX) + return yaml_parser_set_reader_error(parser, "input is too long", + PTRDIFF_MAX, -1); + + return 1; +} + diff --git a/libyaml/src/scanner.c b/libyaml/src/scanner.c new file mode 100644 index 00000000..8817de24 --- /dev/null +++ b/libyaml/src/scanner.c @@ -0,0 +1,3580 @@ + +/* + * Introduction + * ************ + * + * The following notes assume that you are familiar with the YAML specification + * (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in + * some cases we are less restrictive that it requires. + * + * The process of transforming a YAML stream into a sequence of events is + * divided on two steps: Scanning and Parsing. + * + * The Scanner transforms the input stream into a sequence of tokens, while the + * parser transform the sequence of tokens produced by the Scanner into a + * sequence of parsing events. + * + * The Scanner is rather clever and complicated. The Parser, on the contrary, + * is a straightforward implementation of a recursive-descendant parser (or, + * LL(1) parser, as it is usually called). + * + * Actually there are two issues of Scanning that might be called "clever", the + * rest is quite straightforward. The issues are "block collection start" and + * "simple keys". Both issues are explained below in details. + * + * Here the Scanning step is explained and implemented. We start with the list + * of all the tokens produced by the Scanner together with short descriptions. + * + * Now, tokens: + * + * STREAM-START(encoding) # The stream start. + * STREAM-END # The stream end. + * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. + * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. + * DOCUMENT-START # '---' + * DOCUMENT-END # '...' + * BLOCK-SEQUENCE-START # Indentation increase denoting a block + * BLOCK-MAPPING-START # sequence or a block mapping. + * BLOCK-END # Indentation decrease. + * FLOW-SEQUENCE-START # '[' + * FLOW-SEQUENCE-END # ']' + * BLOCK-SEQUENCE-START # '{' + * BLOCK-SEQUENCE-END # '}' + * BLOCK-ENTRY # '-' + * FLOW-ENTRY # ',' + * KEY # '?' or nothing (simple keys). + * VALUE # ':' + * ALIAS(anchor) # '*anchor' + * ANCHOR(anchor) # '&anchor' + * TAG(handle,suffix) # '!handle!suffix' + * SCALAR(value,style) # A scalar. + * + * The following two tokens are "virtual" tokens denoting the beginning and the + * end of the stream: + * + * STREAM-START(encoding) + * STREAM-END + * + * We pass the information about the input stream encoding with the + * STREAM-START token. + * + * The next two tokens are responsible for tags: + * + * VERSION-DIRECTIVE(major,minor) + * TAG-DIRECTIVE(handle,prefix) + * + * Example: + * + * %YAML 1.1 + * %TAG ! !foo + * %TAG !yaml! tag:yaml.org,2002: + * --- + * + * The correspoding sequence of tokens: + * + * STREAM-START(utf-8) + * VERSION-DIRECTIVE(1,1) + * TAG-DIRECTIVE("!","!foo") + * TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") + * DOCUMENT-START + * STREAM-END + * + * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole + * line. + * + * The document start and end indicators are represented by: + * + * DOCUMENT-START + * DOCUMENT-END + * + * Note that if a YAML stream contains an implicit document (without '---' + * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be + * produced. + * + * In the following examples, we present whole documents together with the + * produced tokens. + * + * 1. An implicit document: + * + * 'a scalar' + * + * Tokens: + * + * STREAM-START(utf-8) + * SCALAR("a scalar",single-quoted) + * STREAM-END + * + * 2. An explicit document: + * + * --- + * 'a scalar' + * ... + * + * Tokens: + * + * STREAM-START(utf-8) + * DOCUMENT-START + * SCALAR("a scalar",single-quoted) + * DOCUMENT-END + * STREAM-END + * + * 3. Several documents in a stream: + * + * 'a scalar' + * --- + * 'another scalar' + * --- + * 'yet another scalar' + * + * Tokens: + * + * STREAM-START(utf-8) + * SCALAR("a scalar",single-quoted) + * DOCUMENT-START + * SCALAR("another scalar",single-quoted) + * DOCUMENT-START + * SCALAR("yet another scalar",single-quoted) + * STREAM-END + * + * We have already introduced the SCALAR token above. The following tokens are + * used to describe aliases, anchors, tag, and scalars: + * + * ALIAS(anchor) + * ANCHOR(anchor) + * TAG(handle,suffix) + * SCALAR(value,style) + * + * The following series of examples illustrate the usage of these tokens: + * + * 1. A recursive sequence: + * + * &A [ *A ] + * + * Tokens: + * + * STREAM-START(utf-8) + * ANCHOR("A") + * FLOW-SEQUENCE-START + * ALIAS("A") + * FLOW-SEQUENCE-END + * STREAM-END + * + * 2. A tagged scalar: + * + * !!float "3.14" # A good approximation. + * + * Tokens: + * + * STREAM-START(utf-8) + * TAG("!!","float") + * SCALAR("3.14",double-quoted) + * STREAM-END + * + * 3. Various scalar styles: + * + * --- # Implicit empty plain scalars do not produce tokens. + * --- a plain scalar + * --- 'a single-quoted scalar' + * --- "a double-quoted scalar" + * --- |- + * a literal scalar + * --- >- + * a folded + * scalar + * + * Tokens: + * + * STREAM-START(utf-8) + * DOCUMENT-START + * DOCUMENT-START + * SCALAR("a plain scalar",plain) + * DOCUMENT-START + * SCALAR("a single-quoted scalar",single-quoted) + * DOCUMENT-START + * SCALAR("a double-quoted scalar",double-quoted) + * DOCUMENT-START + * SCALAR("a literal scalar",literal) + * DOCUMENT-START + * SCALAR("a folded scalar",folded) + * STREAM-END + * + * Now it's time to review collection-related tokens. We will start with + * flow collections: + * + * FLOW-SEQUENCE-START + * FLOW-SEQUENCE-END + * FLOW-MAPPING-START + * FLOW-MAPPING-END + * FLOW-ENTRY + * KEY + * VALUE + * + * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and + * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' + * correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the + * indicators '?' and ':', which are used for denoting mapping keys and values, + * are represented by the KEY and VALUE tokens. + * + * The following examples show flow collections: + * + * 1. A flow sequence: + * + * [item 1, item 2, item 3] + * + * Tokens: + * + * STREAM-START(utf-8) + * FLOW-SEQUENCE-START + * SCALAR("item 1",plain) + * FLOW-ENTRY + * SCALAR("item 2",plain) + * FLOW-ENTRY + * SCALAR("item 3",plain) + * FLOW-SEQUENCE-END + * STREAM-END + * + * 2. A flow mapping: + * + * { + * a simple key: a value, # Note that the KEY token is produced. + * ? a complex key: another value, + * } + * + * Tokens: + * + * STREAM-START(utf-8) + * FLOW-MAPPING-START + * KEY + * SCALAR("a simple key",plain) + * VALUE + * SCALAR("a value",plain) + * FLOW-ENTRY + * KEY + * SCALAR("a complex key",plain) + * VALUE + * SCALAR("another value",plain) + * FLOW-ENTRY + * FLOW-MAPPING-END + * STREAM-END + * + * A simple key is a key which is not denoted by the '?' indicator. Note that + * the Scanner still produce the KEY token whenever it encounters a simple key. + * + * For scanning block collections, the following tokens are used (note that we + * repeat KEY and VALUE here): + * + * BLOCK-SEQUENCE-START + * BLOCK-MAPPING-START + * BLOCK-END + * BLOCK-ENTRY + * KEY + * VALUE + * + * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation + * increase that precedes a block collection (cf. the INDENT token in Python). + * The token BLOCK-END denote indentation decrease that ends a block collection + * (cf. the DEDENT token in Python). However YAML has some syntax pecularities + * that makes detections of these tokens more complex. + * + * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators + * '-', '?', and ':' correspondingly. + * + * The following examples show how the tokens BLOCK-SEQUENCE-START, + * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: + * + * 1. Block sequences: + * + * - item 1 + * - item 2 + * - + * - item 3.1 + * - item 3.2 + * - + * key 1: value 1 + * key 2: value 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-ENTRY + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 3.1",plain) + * BLOCK-ENTRY + * SCALAR("item 3.2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * 2. Block mappings: + * + * a simple key: a value # The KEY token is produced here. + * ? a complex key + * : another value + * a mapping: + * key 1: value 1 + * key 2: value 2 + * a sequence: + * - item 1 + * - item 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("a simple key",plain) + * VALUE + * SCALAR("a value",plain) + * KEY + * SCALAR("a complex key",plain) + * VALUE + * SCALAR("another value",plain) + * KEY + * SCALAR("a mapping",plain) + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * KEY + * SCALAR("a sequence",plain) + * VALUE + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * YAML does not always require to start a new block collection from a new + * line. If the current line contains only '-', '?', and ':' indicators, a new + * block collection may start at the current line. The following examples + * illustrate this case: + * + * 1. Collections in a sequence: + * + * - - item 1 + * - item 2 + * - key 1: value 1 + * key 2: value 2 + * - ? complex key + * : complex value + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("complex key") + * VALUE + * SCALAR("complex value") + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * 2. Collections in a mapping: + * + * ? a sequence + * : - item 1 + * - item 2 + * ? a mapping + * : key 1: value 1 + * key 2: value 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("a sequence",plain) + * VALUE + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * KEY + * SCALAR("a mapping",plain) + * VALUE + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * YAML also permits non-indented sequences if they are included into a block + * mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: + * + * key: + * - item 1 # BLOCK-SEQUENCE-START is NOT produced here. + * - item 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("key",plain) + * VALUE + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + */ + +#include "yaml_private.h" + +/* + * Ensure that the buffer contains the required number of characters. + * Return 1 on success, 0 on failure (reader error or memory error). + */ + +#define CACHE(parser,length) \ + (parser->unread >= (length) \ + ? 1 \ + : yaml_parser_update_buffer(parser, (length))) + +/* + * Advance the buffer pointer. + */ + +#define SKIP(parser) \ + (parser->mark.index ++, \ + parser->mark.column ++, \ + parser->unread --, \ + parser->buffer.pointer += WIDTH(parser->buffer)) + +#define SKIP_LINE(parser) \ + (IS_CRLF(parser->buffer) ? \ + (parser->mark.index += 2, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread -= 2, \ + parser->buffer.pointer += 2) : \ + IS_BREAK(parser->buffer) ? \ + (parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --, \ + parser->buffer.pointer += WIDTH(parser->buffer)) : 0) + +/* + * Copy a character to a string buffer and advance pointers. + */ + +#define READ(parser,string) \ + (STRING_EXTEND(parser,string) ? \ + (COPY(string,parser->buffer), \ + parser->mark.index ++, \ + parser->mark.column ++, \ + parser->unread --, \ + 1) : 0) + +/* + * Copy a line break character to a string buffer and advance pointers. + */ + +#define READ_LINE(parser,string) \ + (STRING_EXTEND(parser,string) ? \ + (((CHECK_AT(parser->buffer,'\r',0) \ + && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer += 2, \ + parser->mark.index += 2, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread -= 2) : \ + (CHECK_AT(parser->buffer,'\r',0) \ + || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer ++, \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : \ + (CHECK_AT(parser->buffer,'\xC2',0) \ + && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer += 2, \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : \ + (CHECK_AT(parser->buffer,'\xE2',0) && \ + CHECK_AT(parser->buffer,'\x80',1) && \ + (CHECK_AT(parser->buffer,'\xA8',2) || \ + CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \ + (*((string).pointer++) = *(parser->buffer.pointer++), \ + *((string).pointer++) = *(parser->buffer.pointer++), \ + *((string).pointer++) = *(parser->buffer.pointer++), \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : 0), \ + 1) : 0) + +/* + * Public API declarations. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); + +/* + * Error handling. + */ + +static int +yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, + yaml_mark_t context_mark, const char *problem); + +/* + * High-level token API. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +static int +yaml_parser_fetch_next_token(yaml_parser_t *parser); + +/* + * Potential simple keys. + */ + +static int +yaml_parser_stale_simple_keys(yaml_parser_t *parser); + +static int +yaml_parser_save_simple_key(yaml_parser_t *parser); + +static int +yaml_parser_remove_simple_key(yaml_parser_t *parser); + +static int +yaml_parser_increase_flow_level(yaml_parser_t *parser); + +static int +yaml_parser_decrease_flow_level(yaml_parser_t *parser); + +/* + * Indentation treatment. + */ + +static int +yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, + ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark); + +static int +yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column); + +/* + * Token fetchers. + */ + +static int +yaml_parser_fetch_stream_start(yaml_parser_t *parser); + +static int +yaml_parser_fetch_stream_end(yaml_parser_t *parser); + +static int +yaml_parser_fetch_directive(yaml_parser_t *parser); + +static int +yaml_parser_fetch_document_indicator(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_entry(yaml_parser_t *parser); + +static int +yaml_parser_fetch_block_entry(yaml_parser_t *parser); + +static int +yaml_parser_fetch_key(yaml_parser_t *parser); + +static int +yaml_parser_fetch_value(yaml_parser_t *parser); + +static int +yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type); + +static int +yaml_parser_fetch_tag(yaml_parser_t *parser); + +static int +yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal); + +static int +yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single); + +static int +yaml_parser_fetch_plain_scalar(yaml_parser_t *parser); + +/* + * Token scanners. + */ + +static int +yaml_parser_scan_to_next_token(yaml_parser_t *parser); + +static int +yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token); + +static int +yaml_parser_scan_directive_name(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **name); + +static int +yaml_parser_scan_version_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, int *major, int *minor); + +static int +yaml_parser_scan_version_directive_number(yaml_parser_t *parser, + yaml_mark_t start_mark, int *number); + +static int +yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, + yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix); + +static int +yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, + yaml_token_type_t type); + +static int +yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token); + +static int +yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_char_t **handle); + +static int +yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, + yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri); + +static int +yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_string_t *string); + +static int +yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, + int literal); + +static int +yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, + int *indent, yaml_string_t *breaks, + yaml_mark_t start_mark, yaml_mark_t *end_mark); + +static int +yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, + int single); + +static int +yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token); + +/* + * Get the next token. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token) +{ + assert(parser); /* Non-NULL parser object is expected. */ + assert(token); /* Non-NULL token object is expected. */ + + /* Erase the token object. */ + + memset(token, 0, sizeof(yaml_token_t)); + + /* No tokens after STREAM-END or error. */ + + if (parser->stream_end_produced || parser->error) { + return 1; + } + + /* Ensure that the tokens queue contains enough tokens. */ + + if (!parser->token_available) { + if (!yaml_parser_fetch_more_tokens(parser)) + return 0; + } + + /* Fetch the next token from the queue. */ + + *token = DEQUEUE(parser, parser->tokens); + parser->token_available = 0; + parser->tokens_parsed ++; + + if (token->type == YAML_STREAM_END_TOKEN) { + parser->stream_end_produced = 1; + } + + return 1; +} + +/* + * Set the scanner error and return 0. + */ + +static int +yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, + yaml_mark_t context_mark, const char *problem) +{ + parser->error = YAML_SCANNER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = parser->mark; + + return 0; +} + +/* + * Ensure that the tokens queue contains at least one token which can be + * returned to the Parser. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser) +{ + int need_more_tokens; + + /* While we need more tokens to fetch, do it. */ + + while (1) + { + /* + * Check if we really need to fetch more tokens. + */ + + need_more_tokens = 0; + + if (parser->tokens.head == parser->tokens.tail) + { + /* Queue is empty. */ + + need_more_tokens = 1; + } + else + { + yaml_simple_key_t *simple_key; + + /* Check if any potential simple key may occupy the head position. */ + + if (!yaml_parser_stale_simple_keys(parser)) + return 0; + + for (simple_key = parser->simple_keys.start; + simple_key != parser->simple_keys.top; simple_key++) { + if (simple_key->possible + && simple_key->token_number == parser->tokens_parsed) { + need_more_tokens = 1; + break; + } + } + } + + /* We are finished. */ + + if (!need_more_tokens) + break; + + /* Fetch the next token. */ + + if (!yaml_parser_fetch_next_token(parser)) + return 0; + } + + parser->token_available = 1; + + return 1; +} + +/* + * The dispatcher for token fetchers. + */ + +static int +yaml_parser_fetch_next_token(yaml_parser_t *parser) +{ + /* Ensure that the buffer is initialized. */ + + if (!CACHE(parser, 1)) + return 0; + + /* Check if we just started scanning. Fetch STREAM-START then. */ + + if (!parser->stream_start_produced) + return yaml_parser_fetch_stream_start(parser); + + /* Eat whitespaces and comments until we reach the next token. */ + + if (!yaml_parser_scan_to_next_token(parser)) + return 0; + + /* Remove obsolete potential simple keys. */ + + if (!yaml_parser_stale_simple_keys(parser)) + return 0; + + /* Check the indentation level against the current column. */ + + if (!yaml_parser_unroll_indent(parser, parser->mark.column)) + return 0; + + /* + * Ensure that the buffer contains at least 4 characters. 4 is the length + * of the longest indicators ('--- ' and '... '). + */ + + if (!CACHE(parser, 4)) + return 0; + + /* Is it the end of the stream? */ + + if (IS_Z(parser->buffer)) + return yaml_parser_fetch_stream_end(parser); + + /* Is it a directive? */ + + if (parser->mark.column == 0 && CHECK(parser->buffer, '%')) + return yaml_parser_fetch_directive(parser); + + /* Is it the document start indicator? */ + + if (parser->mark.column == 0 + && CHECK_AT(parser->buffer, '-', 0) + && CHECK_AT(parser->buffer, '-', 1) + && CHECK_AT(parser->buffer, '-', 2) + && IS_BLANKZ_AT(parser->buffer, 3)) + return yaml_parser_fetch_document_indicator(parser, + YAML_DOCUMENT_START_TOKEN); + + /* Is it the document end indicator? */ + + if (parser->mark.column == 0 + && CHECK_AT(parser->buffer, '.', 0) + && CHECK_AT(parser->buffer, '.', 1) + && CHECK_AT(parser->buffer, '.', 2) + && IS_BLANKZ_AT(parser->buffer, 3)) + return yaml_parser_fetch_document_indicator(parser, + YAML_DOCUMENT_END_TOKEN); + + /* Is it the flow sequence start indicator? */ + + if (CHECK(parser->buffer, '[')) + return yaml_parser_fetch_flow_collection_start(parser, + YAML_FLOW_SEQUENCE_START_TOKEN); + + /* Is it the flow mapping start indicator? */ + + if (CHECK(parser->buffer, '{')) + return yaml_parser_fetch_flow_collection_start(parser, + YAML_FLOW_MAPPING_START_TOKEN); + + /* Is it the flow sequence end indicator? */ + + if (CHECK(parser->buffer, ']')) + return yaml_parser_fetch_flow_collection_end(parser, + YAML_FLOW_SEQUENCE_END_TOKEN); + + /* Is it the flow mapping end indicator? */ + + if (CHECK(parser->buffer, '}')) + return yaml_parser_fetch_flow_collection_end(parser, + YAML_FLOW_MAPPING_END_TOKEN); + + /* Is it the flow entry indicator? */ + + if (CHECK(parser->buffer, ',')) + return yaml_parser_fetch_flow_entry(parser); + + /* Is it the block entry indicator? */ + + if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1)) + return yaml_parser_fetch_block_entry(parser); + + /* Is it the key indicator? */ + + if (CHECK(parser->buffer, '?') + && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_key(parser); + + /* Is it the value indicator? */ + + if (CHECK(parser->buffer, ':') + && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_value(parser); + + /* Is it an alias? */ + + if (CHECK(parser->buffer, '*')) + return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN); + + /* Is it an anchor? */ + + if (CHECK(parser->buffer, '&')) + return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN); + + /* Is it a tag? */ + + if (CHECK(parser->buffer, '!')) + return yaml_parser_fetch_tag(parser); + + /* Is it a literal scalar? */ + + if (CHECK(parser->buffer, '|') && !parser->flow_level) + return yaml_parser_fetch_block_scalar(parser, 1); + + /* Is it a folded scalar? */ + + if (CHECK(parser->buffer, '>') && !parser->flow_level) + return yaml_parser_fetch_block_scalar(parser, 0); + + /* Is it a single-quoted scalar? */ + + if (CHECK(parser->buffer, '\'')) + return yaml_parser_fetch_flow_scalar(parser, 1); + + /* Is it a double-quoted scalar? */ + + if (CHECK(parser->buffer, '"')) + return yaml_parser_fetch_flow_scalar(parser, 0); + + /* + * Is it a plain scalar? + * + * A plain scalar may start with any non-blank characters except + * + * '-', '?', ':', ',', '[', ']', '{', '}', + * '#', '&', '*', '!', '|', '>', '\'', '\"', + * '%', '@', '`'. + * + * In the block context (and, for the '-' indicator, in the flow context + * too), it may also start with the characters + * + * '-', '?', ':' + * + * if it is followed by a non-space character. + * + * The last rule is more restrictive than the specification requires. + */ + + if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-') + || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':') + || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') + || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#') + || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*') + || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|') + || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'') + || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%') + || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) || + (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) || + (!parser->flow_level && + (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')) + && !IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_plain_scalar(parser); + + /* + * If we don't determine the token type so far, it is an error. + */ + + return yaml_parser_set_scanner_error(parser, + "while scanning for the next token", parser->mark, + "found character that cannot start any token"); +} + +/* + * Check the list of potential simple keys and remove the positions that + * cannot contain simple keys anymore. + */ + +static int +yaml_parser_stale_simple_keys(yaml_parser_t *parser) +{ + yaml_simple_key_t *simple_key; + + /* Check for a potential simple key for each flow level. */ + + for (simple_key = parser->simple_keys.start; + simple_key != parser->simple_keys.top; simple_key ++) + { + /* + * The specification requires that a simple key + * + * - is limited to a single line, + * - is shorter than 1024 characters. + */ + + if (simple_key->possible + && (simple_key->mark.line < parser->mark.line + || simple_key->mark.index+1024 < parser->mark.index)) { + + /* Check if the potential simple key to be removed is required. */ + + if (simple_key->required) { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key->mark, + "could not find expected ':'"); + } + + simple_key->possible = 0; + } + } + + return 1; +} + +/* + * Check if a simple key may start at the current position and add it if + * needed. + */ + +static int +yaml_parser_save_simple_key(yaml_parser_t *parser) +{ + /* + * A simple key is required at the current position if the scanner is in + * the block context and the current column coincides with the indentation + * level. + */ + + int required = (!parser->flow_level + && parser->indent == (ptrdiff_t)parser->mark.column); + + /* + * A simple key is required only when it is the first token in the current + * line. Therefore it is always allowed. But we add a check anyway. + */ + + assert(parser->simple_key_allowed || !required); /* Impossible. */ + + /* + * If the current position may start a simple key, save it. + */ + + if (parser->simple_key_allowed) + { + yaml_simple_key_t simple_key; + simple_key.possible = 1; + simple_key.required = required; + simple_key.token_number = + parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head); + simple_key.mark = parser->mark; + + if (!yaml_parser_remove_simple_key(parser)) return 0; + + *(parser->simple_keys.top-1) = simple_key; + } + + return 1; +} + +/* + * Remove a potential simple key at the current flow level. + */ + +static int +yaml_parser_remove_simple_key(yaml_parser_t *parser) +{ + yaml_simple_key_t *simple_key = parser->simple_keys.top-1; + + if (simple_key->possible) + { + /* If the key is required, it is an error. */ + + if (simple_key->required) { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key->mark, + "could not find expected ':'"); + } + } + + /* Remove the key from the stack. */ + + simple_key->possible = 0; + + return 1; +} + +/* + * Increase the flow level and resize the simple key list if needed. + */ + +static int +yaml_parser_increase_flow_level(yaml_parser_t *parser) +{ + yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } }; + + /* Reset the simple key on the next level. */ + + if (!PUSH(parser, parser->simple_keys, empty_simple_key)) + return 0; + + /* Increase the flow level. */ + + if (parser->flow_level == INT_MAX) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + + parser->flow_level++; + + return 1; +} + +/* + * Decrease the flow level. + */ + +static int +yaml_parser_decrease_flow_level(yaml_parser_t *parser) +{ + yaml_simple_key_t dummy_key; /* Used to eliminate a compiler warning. */ + + if (parser->flow_level) { + parser->flow_level --; + dummy_key = POP(parser, parser->simple_keys); + } + + return 1; +} + +/* + * Push the current indentation level to the stack and set the new level + * the current column is greater than the indentation level. In this case, + * append or insert the specified token into the token queue. + * + */ + +static int +yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, + ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark) +{ + yaml_token_t token; + + /* In the flow context, do nothing. */ + + if (parser->flow_level) + return 1; + + if (parser->indent < column) + { + /* + * Push the current indentation level to the stack and set the new + * indentation level. + */ + + if (!PUSH(parser, parser->indents, parser->indent)) + return 0; + + if (column > INT_MAX) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + + parser->indent = column; + + /* Create a token and insert it into the queue. */ + + TOKEN_INIT(token, type, mark, mark); + + if (number == -1) { + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + } + else { + if (!QUEUE_INSERT(parser, + parser->tokens, number - parser->tokens_parsed, token)) + return 0; + } + } + + return 1; +} + +/* + * Pop indentation levels from the indents stack until the current level + * becomes less or equal to the column. For each intendation level, append + * the BLOCK-END token. + */ + + +static int +yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column) +{ + yaml_token_t token; + + /* In the flow context, do nothing. */ + + if (parser->flow_level) + return 1; + + /* Loop through the intendation levels in the stack. */ + + while (parser->indent > column) + { + /* Create a token and append it to the queue. */ + + TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + /* Pop the indentation level. */ + + parser->indent = POP(parser, parser->indents); + } + + return 1; +} + +/* + * Initialize the scanner and produce the STREAM-START token. + */ + +static int +yaml_parser_fetch_stream_start(yaml_parser_t *parser) +{ + yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } }; + yaml_token_t token; + + /* Set the initial indentation. */ + + parser->indent = -1; + + /* Initialize the simple key stack. */ + + if (!PUSH(parser, parser->simple_keys, simple_key)) + return 0; + + /* A simple key is allowed at the beginning of the stream. */ + + parser->simple_key_allowed = 1; + + /* We have started. */ + + parser->stream_start_produced = 1; + + /* Create the STREAM-START token and append it to the queue. */ + + STREAM_START_TOKEN_INIT(token, parser->encoding, + parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the STREAM-END token and shut down the scanner. + */ + +static int +yaml_parser_fetch_stream_end(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* Force new line. */ + + if (parser->mark.column != 0) { + parser->mark.column = 0; + parser->mark.line ++; + } + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Create the STREAM-END token and append it to the queue. */ + + STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. + */ + +static int +yaml_parser_fetch_directive(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */ + + if (!yaml_parser_scan_directive(parser, &token)) + return 0; + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the DOCUMENT-START or DOCUMENT-END token. + */ + +static int +yaml_parser_fetch_document_indicator(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Consume the token. */ + + start_mark = parser->mark; + + SKIP(parser); + SKIP(parser); + SKIP(parser); + + end_mark = parser->mark; + + /* Create the DOCUMENT-START or DOCUMENT-END token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. + */ + +static int +yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* The indicators '[' and '{' may start a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* Increase the flow level. */ + + if (!yaml_parser_increase_flow_level(parser)) + return 0; + + /* A simple key may follow the indicators '[' and '{'. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. + */ + +static int +yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset any potential simple key on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Decrease the flow level. */ + + if (!yaml_parser_decrease_flow_level(parser)) + return 0; + + /* No simple keys after the indicators ']' and '}'. */ + + parser->simple_key_allowed = 0; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-ENTRY token. + */ + +static int +yaml_parser_fetch_flow_entry(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after ','. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-ENTRY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the BLOCK-ENTRY token. + */ + +static int +yaml_parser_fetch_block_entry(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Check if the scanner is in the block context. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a new entry. */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "block sequence entries are not allowed in this context"); + } + + /* Add the BLOCK-SEQUENCE-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark)) + return 0; + } + else + { + /* + * It is an error for the '-' indicator to occur in the flow context, + * but we let the Parser detect and report about it because the Parser + * is able to point to the context. + */ + } + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after '-'. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the BLOCK-ENTRY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the KEY token. + */ + +static int +yaml_parser_fetch_key(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* In the block context, additional checks are required. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a new key (not nessesary simple). */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "mapping keys are not allowed in this context"); + } + + /* Add the BLOCK-MAPPING-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) + return 0; + } + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after '?' in the block context. */ + + parser->simple_key_allowed = (!parser->flow_level); + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the KEY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the VALUE token. + */ + +static int +yaml_parser_fetch_value(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + yaml_simple_key_t *simple_key = parser->simple_keys.top-1; + + /* Have we found a simple key? */ + + if (simple_key->possible) + { + + /* Create the KEY token and insert it into the queue. */ + + TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark); + + if (!QUEUE_INSERT(parser, parser->tokens, + simple_key->token_number - parser->tokens_parsed, token)) + return 0; + + /* In the block context, we may need to add the BLOCK-MAPPING-START token. */ + + if (!yaml_parser_roll_indent(parser, simple_key->mark.column, + simple_key->token_number, + YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark)) + return 0; + + /* Remove the simple key. */ + + simple_key->possible = 0; + + /* A simple key cannot follow another simple key. */ + + parser->simple_key_allowed = 0; + } + else + { + /* The ':' indicator follows a complex key. */ + + /* In the block context, extra checks are required. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a complex value. */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "mapping values are not allowed in this context"); + } + + /* Add the BLOCK-MAPPING-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) + return 0; + } + + /* Simple keys after ':' are allowed in the block context. */ + + parser->simple_key_allowed = (!parser->flow_level); + } + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the VALUE token and append it to the queue. */ + + TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the ALIAS or ANCHOR token. + */ + +static int +yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type) +{ + yaml_token_t token; + + /* An anchor or an alias could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow an anchor or an alias. */ + + parser->simple_key_allowed = 0; + + /* Create the ALIAS or ANCHOR token and append it to the queue. */ + + if (!yaml_parser_scan_anchor(parser, &token, type)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + return 1; +} + +/* + * Produce the TAG token. + */ + +static int +yaml_parser_fetch_tag(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* A tag could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a tag. */ + + parser->simple_key_allowed = 0; + + /* Create the TAG token and append it to the queue. */ + + if (!yaml_parser_scan_tag(parser, &token)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. + */ + +static int +yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal) +{ + yaml_token_t token; + + /* Remove any potential simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* A simple key may follow a block scalar. */ + + parser->simple_key_allowed = 1; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_block_scalar(parser, &token, literal)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. + */ + +static int +yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single) +{ + yaml_token_t token; + + /* A plain scalar could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a flow scalar. */ + + parser->simple_key_allowed = 0; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_flow_scalar(parser, &token, single)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,plain) token. + */ + +static int +yaml_parser_fetch_plain_scalar(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* A plain scalar could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a flow scalar. */ + + parser->simple_key_allowed = 0; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_plain_scalar(parser, &token)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Eat whitespaces and comments until the next token is found. + */ + +static int +yaml_parser_scan_to_next_token(yaml_parser_t *parser) +{ + /* Until the next token is not found. */ + + while (1) + { + /* Allow the BOM mark to start a line. */ + + if (!CACHE(parser, 1)) return 0; + + if (parser->mark.column == 0 && IS_BOM(parser->buffer)) + SKIP(parser); + + /* + * Eat whitespaces. + * + * Tabs are allowed: + * + * - in the flow context; + * - in the block context, but not at the beginning of the line or + * after '-', '?', or ':' (complex value). + */ + + if (!CACHE(parser, 1)) return 0; + + while (CHECK(parser->buffer,' ') || + ((parser->flow_level || !parser->simple_key_allowed) && + CHECK(parser->buffer, '\t'))) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + /* Eat a comment until a line break. */ + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + } + + /* If it is a line break, eat it. */ + + if (IS_BREAK(parser->buffer)) + { + if (!CACHE(parser, 2)) return 0; + SKIP_LINE(parser); + + /* In the block context, a new line may start a simple key. */ + + if (!parser->flow_level) { + parser->simple_key_allowed = 1; + } + } + else + { + /* We have found a token. */ + + break; + } + } + + return 1; +} + +/* + * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +int +yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_mark_t start_mark, end_mark; + yaml_char_t *name = NULL; + int major, minor; + yaml_char_t *handle = NULL, *prefix = NULL; + + /* Eat '%'. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Scan the directive name. */ + + if (!yaml_parser_scan_directive_name(parser, start_mark, &name)) + goto error; + + /* Is it a YAML directive? */ + + if (strcmp((char *)name, "YAML") == 0) + { + /* Scan the VERSION directive value. */ + + if (!yaml_parser_scan_version_directive_value(parser, start_mark, + &major, &minor)) + goto error; + + end_mark = parser->mark; + + /* Create a VERSION-DIRECTIVE token. */ + + VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor, + start_mark, end_mark); + } + + /* Is it a TAG directive? */ + + else if (strcmp((char *)name, "TAG") == 0) + { + /* Scan the TAG directive value. */ + + if (!yaml_parser_scan_tag_directive_value(parser, start_mark, + &handle, &prefix)) + goto error; + + end_mark = parser->mark; + + /* Create a TAG-DIRECTIVE token. */ + + TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix, + start_mark, end_mark); + } + + /* Unknown directive. */ + + else + { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found uknown directive name"); + goto error; + } + + /* Eat the rest of the line including any comments. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + } + + /* Check if we are at the end of the line. */ + + if (!IS_BREAKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "did not find expected comment or line break"); + goto error; + } + + /* Eat a line break. */ + + if (IS_BREAK(parser->buffer)) { + if (!CACHE(parser, 2)) goto error; + SKIP_LINE(parser); + } + + yaml_free(name); + + return 1; + +error: + yaml_free(prefix); + yaml_free(handle); + yaml_free(name); + return 0; +} + +/* + * Scan the directive name. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^ + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^ + */ + +static int +yaml_parser_scan_directive_name(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **name) +{ + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Consume the directive name. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) + { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the name is empty. */ + + if (string.start == string.pointer) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "could not find expected directive name"); + goto error; + } + + /* Check for an blank character after the name. */ + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unexpected non-alphabetical character"); + goto error; + } + + *name = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan the value of VERSION-DIRECTIVE. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^^^ + */ + +static int +yaml_parser_scan_version_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, int *major, int *minor) +{ + /* Eat whitespaces. */ + + if (!CACHE(parser, 1)) return 0; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + /* Consume the major version number. */ + + if (!yaml_parser_scan_version_directive_number(parser, start_mark, major)) + return 0; + + /* Eat '.'. */ + + if (!CHECK(parser->buffer, '.')) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected digit or '.' character"); + } + + SKIP(parser); + + /* Consume the minor version number. */ + + if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor)) + return 0; + + return 1; +} + +#define MAX_NUMBER_LENGTH 9 + +/* + * Scan the version number of VERSION-DIRECTIVE. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^ + * %YAML 1.1 # a comment \n + * ^ + */ + +static int +yaml_parser_scan_version_directive_number(yaml_parser_t *parser, + yaml_mark_t start_mark, int *number) +{ + int value = 0; + size_t length = 0; + + /* Repeat while the next character is digit. */ + + if (!CACHE(parser, 1)) return 0; + + while (IS_DIGIT(parser->buffer)) + { + /* Check if the number is too long. */ + + if (++length > MAX_NUMBER_LENGTH) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "found extremely long version number"); + } + + value = value*10 + AS_DIGIT(parser->buffer); + + SKIP(parser); + + if (!CACHE(parser, 1)) return 0; + } + + /* Check if the number was present. */ + + if (!length) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected version number"); + } + + *number = value; + + return 1; +} + +/* + * Scan the value of a TAG-DIRECTIVE token. + * + * Scope: + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +static int +yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix) +{ + yaml_char_t *handle_value = NULL; + yaml_char_t *prefix_value = NULL; + + /* Eat whitespaces. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + /* Scan a handle. */ + + if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value)) + goto error; + + /* Expect a whitespace. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANK(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace"); + goto error; + } + + /* Eat whitespaces. */ + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + /* Scan a prefix. */ + + if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value)) + goto error; + + /* Expect a whitespace or line break. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace or line break"); + goto error; + } + + *handle = handle_value; + *prefix = prefix_value; + + return 1; + +error: + yaml_free(handle_value); + yaml_free(prefix_value); + return 0; +} + +static int +yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, + yaml_token_type_t type) +{ + int length = 0; + yaml_mark_t start_mark, end_mark; + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Eat the indicator character. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Consume the value. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + length ++; + } + + end_mark = parser->mark; + + /* + * Check if length of the anchor is greater than 0 and it is followed by + * a whitespace character or one of the indicators: + * + * '?', ':', ',', ']', '}', '%', '@', '`'. + */ + + if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?') + || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}') + || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@') + || CHECK(parser->buffer, '`'))) { + yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ? + "while scanning an anchor" : "while scanning an alias", start_mark, + "did not find expected alphabetic or numeric character"); + goto error; + } + + /* Create a token. */ + + if (type == YAML_ANCHOR_TOKEN) { + ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark); + } + else { + ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark); + } + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan a TAG token. + */ + +static int +yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_char_t *handle = NULL; + yaml_char_t *suffix = NULL; + yaml_mark_t start_mark, end_mark; + + start_mark = parser->mark; + + /* Check if the tag is in the canonical form. */ + + if (!CACHE(parser, 2)) goto error; + + if (CHECK_AT(parser->buffer, '<', 1)) + { + /* Set the handle to '' */ + + handle = yaml_malloc(1); + if (!handle) goto error; + handle[0] = '\0'; + + /* Eat '!<' */ + + SKIP(parser); + SKIP(parser); + + /* Consume the tag value. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) + goto error; + + /* Check for '>' and eat it. */ + + if (!CHECK(parser->buffer, '>')) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find the expected '>'"); + goto error; + } + + SKIP(parser); + } + else + { + /* The tag has either the '!suffix' or the '!handle!suffix' form. */ + + /* First, try to scan a handle. */ + + if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle)) + goto error; + + /* Check if it is, indeed, handle. */ + + if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!') + { + /* Scan the suffix now. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) + goto error; + } + else + { + /* It wasn't a handle after all. Scan the rest of the tag. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix)) + goto error; + + /* Set the handle to '!'. */ + + yaml_free(handle); + handle = yaml_malloc(2); + if (!handle) goto error; + handle[0] = '!'; + handle[1] = '\0'; + + /* + * A special case: the '!' tag. Set the handle to '' and the + * suffix to '!'. + */ + + if (suffix[0] == '\0') { + yaml_char_t *tmp = handle; + handle = suffix; + suffix = tmp; + } + } + } + + /* Check the character which ends the tag. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find expected whitespace or line break"); + goto error; + } + + end_mark = parser->mark; + + /* Create a token. */ + + TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark); + + return 1; + +error: + yaml_free(handle); + yaml_free(suffix); + return 0; +} + +/* + * Scan a tag handle. + */ + +static int +yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_char_t **handle) +{ + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Check the initial '!' character. */ + + if (!CACHE(parser, 1)) goto error; + + if (!CHECK(parser->buffer, '!')) { + yaml_parser_set_scanner_error(parser, directive ? + "while scanning a tag directive" : "while scanning a tag", + start_mark, "did not find expected '!'"); + goto error; + } + + /* Copy the '!' character. */ + + if (!READ(parser, string)) goto error; + + /* Copy all subsequent alphabetical and numerical characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) + { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the trailing character is '!' and copy it. */ + + if (CHECK(parser->buffer, '!')) + { + if (!READ(parser, string)) goto error; + } + else + { + /* + * It's either the '!' tag or not really a tag handle. If it's a %TAG + * directive, it's an error. If it's a tag token, it must be a part of + * URI. + */ + + if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) { + yaml_parser_set_scanner_error(parser, "while parsing a tag directive", + start_mark, "did not find expected '!'"); + goto error; + } + } + + *handle = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan a tag. + */ + +static int +yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, + yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri) +{ + size_t length = head ? strlen((char *)head) : 0; + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Resize the string to include the head. */ + + while ((size_t)(string.end - string.start) <= length) { + if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + } + + /* + * Copy the head if needed. + * + * Note that we don't copy the leading '!' character. + */ + + if (length > 1) { + memcpy(string.start, head+1, length-1); + string.pointer += length-1; + } + + /* Scan the tag. */ + + if (!CACHE(parser, 1)) goto error; + + /* + * The set of characters that may appear in URI is as follows: + * + * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', + * '%'. + */ + + while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';') + || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?') + || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@') + || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=') + || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$') + || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.') + || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~') + || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'') + || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')') + || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']') + || CHECK(parser->buffer, '%')) + { + /* Check if it is a URI-escape sequence. */ + + if (CHECK(parser->buffer, '%')) { + if (!yaml_parser_scan_uri_escapes(parser, + directive, start_mark, &string)) goto error; + } + else { + if (!READ(parser, string)) goto error; + } + + length ++; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the tag is non-empty. */ + + if (!length) { + if (!STRING_EXTEND(parser, string)) + goto error; + + yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "did not find expected tag URI"); + goto error; + } + + *uri = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Decode an URI-escape sequence corresponding to a single UTF-8 character. + */ + +static int +yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_string_t *string) +{ + int width = 0; + + /* Decode the required number of characters. */ + + do { + + unsigned char octet = 0; + + /* Check for a URI-escaped octet. */ + + if (!CACHE(parser, 3)) return 0; + + if (!(CHECK(parser->buffer, '%') + && IS_HEX_AT(parser->buffer, 1) + && IS_HEX_AT(parser->buffer, 2))) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "did not find URI escaped octet"); + } + + /* Get the octet. */ + + octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2); + + /* If it is the leading octet, determine the length of the UTF-8 sequence. */ + + if (!width) + { + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + if (!width) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "found an incorrect leading UTF-8 octet"); + } + } + else + { + /* Check if the trailing octet is correct. */ + + if ((octet & 0xC0) != 0x80) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "found an incorrect trailing UTF-8 octet"); + } + } + + /* Copy the octet and move the pointers. */ + + *(string->pointer++) = octet; + SKIP(parser); + SKIP(parser); + SKIP(parser); + + } while (--width); + + return 1; +} + +/* + * Scan a block scalar. + */ + +static int +yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, + int literal) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + int chomping = 0; + int increment = 0; + int indent = 0; + int leading_blank = 0; + int trailing_blank = 0; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + + /* Eat the indicator '|' or '>'. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Scan the additional block scalar indicators. */ + + if (!CACHE(parser, 1)) goto error; + + /* Check for a chomping indicator. */ + + if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) + { + /* Set the chomping method and eat the indicator. */ + + chomping = CHECK(parser->buffer, '+') ? +1 : -1; + + SKIP(parser); + + /* Check for an indentation indicator. */ + + if (!CACHE(parser, 1)) goto error; + + if (IS_DIGIT(parser->buffer)) + { + /* Check that the intendation is greater than 0. */ + + if (CHECK(parser->buffer, '0')) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an intendation indicator equal to 0"); + goto error; + } + + /* Get the intendation level and eat the indicator. */ + + increment = AS_DIGIT(parser->buffer); + + SKIP(parser); + } + } + + /* Do the same as above, but in the opposite order. */ + + else if (IS_DIGIT(parser->buffer)) + { + if (CHECK(parser->buffer, '0')) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an intendation indicator equal to 0"); + goto error; + } + + increment = AS_DIGIT(parser->buffer); + + SKIP(parser); + + if (!CACHE(parser, 1)) goto error; + + if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) { + chomping = CHECK(parser->buffer, '+') ? +1 : -1; + + SKIP(parser); + } + } + + /* Eat whitespaces and comments to the end of the line. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + } + + /* Check if we are at the end of the line. */ + + if (!IS_BREAKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "did not find expected comment or line break"); + goto error; + } + + /* Eat a line break. */ + + if (IS_BREAK(parser->buffer)) { + if (!CACHE(parser, 2)) goto error; + SKIP_LINE(parser); + } + + end_mark = parser->mark; + + /* Set the intendation level if it was specified. */ + + if (increment) { + indent = parser->indent >= 0 ? parser->indent+increment : increment; + } + + /* Scan the leading line breaks and determine the indentation level if needed. */ + + if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, + start_mark, &end_mark)) goto error; + + /* Scan the block scalar content. */ + + if (!CACHE(parser, 1)) goto error; + + while ((int)parser->mark.column == indent && !IS_Z(parser->buffer)) + { + /* + * We are at the beginning of a non-empty line. + */ + + /* Is it a trailing whitespace? */ + + trailing_blank = IS_BLANK(parser->buffer); + + /* Check if we need to fold the leading line break. */ + + if (!literal && (*leading_break.start == '\n') + && !leading_blank && !trailing_blank) + { + /* Do we need to join the lines by space? */ + + if (*trailing_breaks.start == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer ++) = ' '; + } + + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + CLEAR(parser, leading_break); + } + + /* Append the remaining line breaks. */ + + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + + /* Is it a leading whitespace? */ + + leading_blank = IS_BLANK(parser->buffer); + + /* Consume the current line. */ + + while (!IS_BREAKZ(parser->buffer)) { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Consume the line break. */ + + if (!CACHE(parser, 2)) goto error; + + if (!READ_LINE(parser, leading_break)) goto error; + + /* Eat the following intendation spaces and line breaks. */ + + if (!yaml_parser_scan_block_scalar_breaks(parser, + &indent, &trailing_breaks, start_mark, &end_mark)) goto error; + } + + /* Chomp the tail. */ + + if (chomping != -1) { + if (!JOIN(parser, string, leading_break)) goto error; + } + if (chomping == 1) { + if (!JOIN(parser, string, trailing_breaks)) goto error; + } + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE, + start_mark, end_mark); + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + + return 0; +} + +/* + * Scan intendation spaces and line breaks for a block scalar. Determine the + * intendation level if needed. + */ + +static int +yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, + int *indent, yaml_string_t *breaks, + yaml_mark_t start_mark, yaml_mark_t *end_mark) +{ + int max_indent = 0; + + *end_mark = parser->mark; + + /* Eat the intendation spaces and line breaks. */ + + while (1) + { + /* Eat the intendation spaces. */ + + if (!CACHE(parser, 1)) return 0; + + while ((!*indent || (int)parser->mark.column < *indent) + && IS_SPACE(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + if ((int)parser->mark.column > max_indent) + max_indent = (int)parser->mark.column; + + /* Check for a tab character messing the intendation. */ + + if ((!*indent || (int)parser->mark.column < *indent) + && IS_TAB(parser->buffer)) { + return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found a tab character where an intendation space is expected"); + } + + /* Have we found a non-empty line? */ + + if (!IS_BREAK(parser->buffer)) break; + + /* Consume the line break. */ + + if (!CACHE(parser, 2)) return 0; + if (!READ_LINE(parser, *breaks)) return 0; + *end_mark = parser->mark; + } + + /* Determine the indentation level if needed. */ + + if (!*indent) { + *indent = max_indent; + if (*indent < parser->indent + 1) + *indent = parser->indent + 1; + if (*indent < 1) + *indent = 1; + } + + return 1; +} + +/* + * Scan a quoted scalar. + */ + +static int +yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, + int single) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + yaml_string_t whitespaces = NULL_STRING; + int leading_blanks; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; + + /* Eat the left quote. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Consume the content of the quoted scalar. */ + + while (1) + { + /* Check that there are no document indicators at the beginning of the line. */ + + if (!CACHE(parser, 4)) goto error; + + if (parser->mark.column == 0 && + ((CHECK_AT(parser->buffer, '-', 0) && + CHECK_AT(parser->buffer, '-', 1) && + CHECK_AT(parser->buffer, '-', 2)) || + (CHECK_AT(parser->buffer, '.', 0) && + CHECK_AT(parser->buffer, '.', 1) && + CHECK_AT(parser->buffer, '.', 2))) && + IS_BLANKZ_AT(parser->buffer, 3)) + { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected document indicator"); + goto error; + } + + /* Check for EOF. */ + + if (IS_Z(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected end of stream"); + goto error; + } + + /* Consume non-blank characters. */ + + if (!CACHE(parser, 2)) goto error; + + leading_blanks = 0; + + while (!IS_BLANKZ(parser->buffer)) + { + /* Check for an escaped single quote. */ + + if (single && CHECK_AT(parser->buffer, '\'', 0) + && CHECK_AT(parser->buffer, '\'', 1)) + { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = '\''; + SKIP(parser); + SKIP(parser); + } + + /* Check for the right quote. */ + + else if (CHECK(parser->buffer, single ? '\'' : '"')) + { + break; + } + + /* Check for an escaped line break. */ + + else if (!single && CHECK(parser->buffer, '\\') + && IS_BREAK_AT(parser->buffer, 1)) + { + if (!CACHE(parser, 3)) goto error; + SKIP(parser); + SKIP_LINE(parser); + leading_blanks = 1; + break; + } + + /* Check for an escape sequence. */ + + else if (!single && CHECK(parser->buffer, '\\')) + { + size_t code_length = 0; + + if (!STRING_EXTEND(parser, string)) goto error; + + /* Check the escape character. */ + + switch (parser->buffer.pointer[1]) + { + case '0': + *(string.pointer++) = '\0'; + break; + + case 'a': + *(string.pointer++) = '\x07'; + break; + + case 'b': + *(string.pointer++) = '\x08'; + break; + + case 't': + case '\t': + *(string.pointer++) = '\x09'; + break; + + case 'n': + *(string.pointer++) = '\x0A'; + break; + + case 'v': + *(string.pointer++) = '\x0B'; + break; + + case 'f': + *(string.pointer++) = '\x0C'; + break; + + case 'r': + *(string.pointer++) = '\x0D'; + break; + + case 'e': + *(string.pointer++) = '\x1B'; + break; + + case ' ': + *(string.pointer++) = '\x20'; + break; + + case '"': + *(string.pointer++) = '"'; + break; + + case '\'': + *(string.pointer++) = '\''; + break; + + case '\\': + *(string.pointer++) = '\\'; + break; + + case 'N': /* NEL (#x85) */ + *(string.pointer++) = '\xC2'; + *(string.pointer++) = '\x85'; + break; + + case '_': /* #xA0 */ + *(string.pointer++) = '\xC2'; + *(string.pointer++) = '\xA0'; + break; + + case 'L': /* LS (#x2028) */ + *(string.pointer++) = '\xE2'; + *(string.pointer++) = '\x80'; + *(string.pointer++) = '\xA8'; + break; + + case 'P': /* PS (#x2029) */ + *(string.pointer++) = '\xE2'; + *(string.pointer++) = '\x80'; + *(string.pointer++) = '\xA9'; + break; + + case 'x': + code_length = 2; + break; + + case 'u': + code_length = 4; + break; + + case 'U': + code_length = 8; + break; + + default: + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found unknown escape character"); + goto error; + } + + SKIP(parser); + SKIP(parser); + + /* Consume an arbitrary escape code. */ + + if (code_length) + { + unsigned int value = 0; + size_t k; + + /* Scan the character value. */ + + if (!CACHE(parser, code_length)) goto error; + + for (k = 0; k < code_length; k ++) { + if (!IS_HEX_AT(parser->buffer, k)) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "did not find expected hexdecimal number"); + goto error; + } + value = (value << 4) + AS_HEX_AT(parser->buffer, k); + } + + /* Check the value and write the character. */ + + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found invalid Unicode character escape code"); + goto error; + } + + if (value <= 0x7F) { + *(string.pointer++) = value; + } + else if (value <= 0x7FF) { + *(string.pointer++) = 0xC0 + (value >> 6); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + else if (value <= 0xFFFF) { + *(string.pointer++) = 0xE0 + (value >> 12); + *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + else { + *(string.pointer++) = 0xF0 + (value >> 18); + *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F); + *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + + /* Advance the pointer. */ + + for (k = 0; k < code_length; k ++) { + SKIP(parser); + } + } + } + + else + { + /* It is a non-escaped non-blank character. */ + + if (!READ(parser, string)) goto error; + } + + if (!CACHE(parser, 2)) goto error; + } + + /* Check if we are at the end of the scalar. */ + + if (CHECK(parser->buffer, single ? '\'' : '"')) + break; + + /* Consume blank characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) + { + if (IS_BLANK(parser->buffer)) + { + /* Consume a space or a tab character. */ + + if (!leading_blanks) { + if (!READ(parser, whitespaces)) goto error; + } + else { + SKIP(parser); + } + } + else + { + if (!CACHE(parser, 2)) goto error; + + /* Check if it is a first line break. */ + + if (!leading_blanks) + { + CLEAR(parser, whitespaces); + if (!READ_LINE(parser, leading_break)) goto error; + leading_blanks = 1; + } + else + { + if (!READ_LINE(parser, trailing_breaks)) goto error; + } + } + if (!CACHE(parser, 1)) goto error; + } + + /* Join the whitespaces or fold line breaks. */ + + if (leading_blanks) + { + /* Do we need to fold line breaks? */ + + if (leading_break.start[0] == '\n') { + if (trailing_breaks.start[0] == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = ' '; + } + else { + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + } + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, leading_break); + CLEAR(parser, trailing_breaks); + } + } + else + { + if (!JOIN(parser, string, whitespaces)) goto error; + CLEAR(parser, whitespaces); + } + } + + /* Eat the right quote. */ + + SKIP(parser); + + end_mark = parser->mark; + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE, + start_mark, end_mark); + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 0; +} + +/* + * Scan a plain scalar. + */ + +static int +yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + yaml_string_t whitespaces = NULL_STRING; + int leading_blanks = 0; + int indent = parser->indent+1; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; + + start_mark = end_mark = parser->mark; + + /* Consume the content of the plain scalar. */ + + while (1) + { + /* Check for a document indicator. */ + + if (!CACHE(parser, 4)) goto error; + + if (parser->mark.column == 0 && + ((CHECK_AT(parser->buffer, '-', 0) && + CHECK_AT(parser->buffer, '-', 1) && + CHECK_AT(parser->buffer, '-', 2)) || + (CHECK_AT(parser->buffer, '.', 0) && + CHECK_AT(parser->buffer, '.', 1) && + CHECK_AT(parser->buffer, '.', 2))) && + IS_BLANKZ_AT(parser->buffer, 3)) break; + + /* Check for a comment. */ + + if (CHECK(parser->buffer, '#')) + break; + + /* Consume non-blank characters. */ + + while (!IS_BLANKZ(parser->buffer)) + { + /* Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". */ + + if (parser->flow_level + && CHECK(parser->buffer, ':') + && !IS_BLANKZ_AT(parser->buffer, 1)) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found unexpected ':'"); + goto error; + } + + /* Check for indicators that may end a plain scalar. */ + + if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1)) + || (parser->flow_level && + (CHECK(parser->buffer, ',') || CHECK(parser->buffer, ':') + || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') + || CHECK(parser->buffer, '}')))) + break; + + /* Check if we need to join whitespaces and breaks. */ + + if (leading_blanks || whitespaces.start != whitespaces.pointer) + { + if (leading_blanks) + { + /* Do we need to fold line breaks? */ + + if (leading_break.start[0] == '\n') { + if (trailing_breaks.start[0] == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = ' '; + } + else { + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + } + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, leading_break); + CLEAR(parser, trailing_breaks); + } + + leading_blanks = 0; + } + else + { + if (!JOIN(parser, string, whitespaces)) goto error; + CLEAR(parser, whitespaces); + } + } + + /* Copy the character. */ + + if (!READ(parser, string)) goto error; + + end_mark = parser->mark; + + if (!CACHE(parser, 2)) goto error; + } + + /* Is it the end? */ + + if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))) + break; + + /* Consume blank characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) + { + if (IS_BLANK(parser->buffer)) + { + /* Check for tab character that abuse intendation. */ + + if (leading_blanks && (int)parser->mark.column < indent + && IS_TAB(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found a tab character that violate intendation"); + goto error; + } + + /* Consume a space or a tab character. */ + + if (!leading_blanks) { + if (!READ(parser, whitespaces)) goto error; + } + else { + SKIP(parser); + } + } + else + { + if (!CACHE(parser, 2)) goto error; + + /* Check if it is a first line break. */ + + if (!leading_blanks) + { + CLEAR(parser, whitespaces); + if (!READ_LINE(parser, leading_break)) goto error; + leading_blanks = 1; + } + else + { + if (!READ_LINE(parser, trailing_breaks)) goto error; + } + } + if (!CACHE(parser, 1)) goto error; + } + + /* Check intendation level. */ + + if (!parser->flow_level && (int)parser->mark.column < indent) + break; + } + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark); + + /* Note that we change the 'simple_key_allowed' flag. */ + + if (leading_blanks) { + parser->simple_key_allowed = 1; + } + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 0; +} + diff --git a/libyaml/src/writer.c b/libyaml/src/writer.c new file mode 100644 index 00000000..b90019f5 --- /dev/null +++ b/libyaml/src/writer.c @@ -0,0 +1,141 @@ + +#include "yaml_private.h" + +/* + * Declarations. + */ + +static int +yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem); + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter); + +/* + * Set the writer error and return 0. + */ + +static int +yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem) +{ + emitter->error = YAML_WRITER_ERROR; + emitter->problem = problem; + + return 0; +} + +/* + * Flush the output buffer. + */ + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter) +{ + int low, high; + + assert(emitter); /* Non-NULL emitter object is expected. */ + assert(emitter->write_handler); /* Write handler must be set. */ + assert(emitter->encoding); /* Output encoding must be set. */ + + emitter->buffer.last = emitter->buffer.pointer; + emitter->buffer.pointer = emitter->buffer.start; + + /* Check if the buffer is empty. */ + + if (emitter->buffer.start == emitter->buffer.last) { + return 1; + } + + /* If the output encoding is UTF-8, we don't need to recode the buffer. */ + + if (emitter->encoding == YAML_UTF8_ENCODING) + { + if (emitter->write_handler(emitter->write_handler_data, + emitter->buffer.start, + emitter->buffer.last - emitter->buffer.start)) { + emitter->buffer.last = emitter->buffer.start; + emitter->buffer.pointer = emitter->buffer.start; + return 1; + } + else { + return yaml_emitter_set_writer_error(emitter, "write error"); + } + } + + /* Recode the buffer into the raw buffer. */ + + low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); + high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); + + while (emitter->buffer.pointer != emitter->buffer.last) + { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t k; + + /* + * See the "reader.c" code for more details on UTF-8 encoding. Note + * that we assume that the buffer contains a valid UTF-8 sequence. + */ + + /* Read the next UTF-8 character. */ + + octet = emitter->buffer.pointer[0]; + + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + + for (k = 1; k < width; k ++) { + octet = emitter->buffer.pointer[k]; + value = (value << 6) + (octet & 0x3F); + } + + emitter->buffer.pointer += width; + + /* Write the character. */ + + if (value < 0x10000) + { + emitter->raw_buffer.last[high] = value >> 8; + emitter->raw_buffer.last[low] = value & 0xFF; + + emitter->raw_buffer.last += 2; + } + else + { + /* Write the character using a surrogate pair (check "reader.c"). */ + + value -= 0x10000; + emitter->raw_buffer.last[high] = 0xD8 + (value >> 18); + emitter->raw_buffer.last[low] = (value >> 10) & 0xFF; + emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF); + emitter->raw_buffer.last[low+2] = value & 0xFF; + + emitter->raw_buffer.last += 4; + } + } + + /* Write the raw buffer. */ + + if (emitter->write_handler(emitter->write_handler_data, + emitter->raw_buffer.start, + emitter->raw_buffer.last - emitter->raw_buffer.start)) { + emitter->buffer.last = emitter->buffer.start; + emitter->buffer.pointer = emitter->buffer.start; + emitter->raw_buffer.last = emitter->raw_buffer.start; + emitter->raw_buffer.pointer = emitter->raw_buffer.start; + return 1; + } + else { + return yaml_emitter_set_writer_error(emitter, "write error"); + } +} + diff --git a/libyaml/src/yaml_private.h b/libyaml/src/yaml_private.h new file mode 100644 index 00000000..9589e052 --- /dev/null +++ b/libyaml/src/yaml_private.h @@ -0,0 +1,657 @@ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#ifndef _MSC_VER +#include +#else +#ifdef _WIN64 +#define PTRDIFF_MAX _I64_MAX +#else +#define PTRDIFF_MAX INT_MAX +#endif +#endif + +/* + * Memory management. + */ + +YAML_DECLARE(void *) +yaml_malloc(size_t size); + +YAML_DECLARE(void *) +yaml_realloc(void *ptr, size_t size); + +YAML_DECLARE(void) +yaml_free(void *ptr); + +YAML_DECLARE(yaml_char_t *) +yaml_strdup(const yaml_char_t *); + +/* + * Reader: Ensure that the buffer contains at least `length` characters. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Scanner: Ensure that the token stack contains at least one token ready. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +/* + * The size of the input raw buffer. + */ + +#define INPUT_RAW_BUFFER_SIZE 16384 + +/* + * The size of the input buffer. + * + * It should be possible to decode the whole raw buffer. + */ + +#define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3) + +/* + * The size of the output buffer. + */ + +#define OUTPUT_BUFFER_SIZE 16384 + +/* + * The size of the output raw buffer. + * + * It should be possible to encode the whole output buffer. + */ + +#define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2) + +/* + * The size of other stacks and queues. + */ + +#define INITIAL_STACK_SIZE 16 +#define INITIAL_QUEUE_SIZE 16 +#define INITIAL_STRING_SIZE 16 + +/* + * Buffer management. + */ + +#define BUFFER_INIT(context,buffer,size) \ + (((buffer).start = yaml_malloc(size)) ? \ + ((buffer).last = (buffer).pointer = (buffer).start, \ + (buffer).end = (buffer).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define BUFFER_DEL(context,buffer) \ + (yaml_free((buffer).start), \ + (buffer).start = (buffer).pointer = (buffer).end = 0) + +/* + * String management. + */ + +typedef struct { + yaml_char_t *start; + yaml_char_t *end; + yaml_char_t *pointer; +} yaml_string_t; + +YAML_DECLARE(int) +yaml_string_extend(yaml_char_t **start, + yaml_char_t **pointer, yaml_char_t **end); + +YAML_DECLARE(int) +yaml_string_join( + yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, + yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end); + +#define NULL_STRING { NULL, NULL, NULL } + +#define STRING(string,length) { (string), (string)+(length), (string) } + +#define STRING_ASSIGN(value,string,length) \ + ((value).start = (string), \ + (value).end = (string)+(length), \ + (value).pointer = (string)) + +#define STRING_INIT(context,string,size) \ + (((string).start = yaml_malloc(size)) ? \ + ((string).pointer = (string).start, \ + (string).end = (string).start+(size), \ + memset((string).start, 0, (size)), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define STRING_DEL(context,string) \ + (yaml_free((string).start), \ + (string).start = (string).pointer = (string).end = 0) + +#define STRING_EXTEND(context,string) \ + (((string).pointer+5 < (string).end) \ + || yaml_string_extend(&(string).start, \ + &(string).pointer, &(string).end)) + +#define CLEAR(context,string) \ + ((string).pointer = (string).start, \ + memset((string).start, 0, (string).end-(string).start)) + +#define JOIN(context,string_a,string_b) \ + ((yaml_string_join(&(string_a).start, &(string_a).pointer, \ + &(string_a).end, &(string_b).start, \ + &(string_b).pointer, &(string_b).end)) ? \ + ((string_b).pointer = (string_b).start, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +/* + * String check operations. + */ + +/* + * Check the octet at the specified position. + */ + +#define CHECK_AT(string,octet,offset) \ + ((string).pointer[offset] == (yaml_char_t)(octet)) + +/* + * Check the current octet in the buffer. + */ + +#define CHECK(string,octet) CHECK_AT((string),(octet),0) + +/* + * Check if the character at the specified position is an alphabetical + * character, a digit, '_', or '-'. + */ + +#define IS_ALPHA_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9') || \ + ((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'Z') || \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'z') || \ + (string).pointer[offset] == '_' || \ + (string).pointer[offset] == '-') + +#define IS_ALPHA(string) IS_ALPHA_AT((string),0) + +/* + * Check if the character at the specified position is a digit. + */ + +#define IS_DIGIT_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9')) + +#define IS_DIGIT(string) IS_DIGIT_AT((string),0) + +/* + * Get the value of a digit. + */ + +#define AS_DIGIT_AT(string,offset) \ + ((string).pointer[offset] - (yaml_char_t) '0') + +#define AS_DIGIT(string) AS_DIGIT_AT((string),0) + +/* + * Check if the character at the specified position is a hex-digit. + */ + +#define IS_HEX_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9') || \ + ((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'F') || \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'f')) + +#define IS_HEX(string) IS_HEX_AT((string),0) + +/* + * Get the value of a hex-digit. + */ + +#define AS_HEX_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'F') ? \ + ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'f') ? \ + ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \ + ((string).pointer[offset] - (yaml_char_t) '0')) + +#define AS_HEX(string) AS_HEX_AT((string),0) + +/* + * Check if the character is ASCII. + */ + +#define IS_ASCII_AT(string,offset) \ + ((string).pointer[offset] <= (yaml_char_t) '\x7F') + +#define IS_ASCII(string) IS_ASCII_AT((string),0) + +/* + * Check if the character can be printed unescaped. + */ + +#define IS_PRINTABLE_AT(string,offset) \ + (((string).pointer[offset] == 0x0A) /* . == #x0A */ \ + || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \ + && (string).pointer[offset] <= 0x7E) \ + || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \ + && (string).pointer[offset+1] >= 0xA0) \ + || ((string).pointer[offset] > 0xC2 \ + && (string).pointer[offset] < 0xED) \ + || ((string).pointer[offset] == 0xED \ + && (string).pointer[offset+1] < 0xA0) \ + || ((string).pointer[offset] == 0xEE) \ + || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \ + && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \ + && (string).pointer[offset+2] == 0xBF) \ + && !((string).pointer[offset+1] == 0xBF \ + && ((string).pointer[offset+2] == 0xBE \ + || (string).pointer[offset+2] == 0xBF)))) + +#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0) + +/* + * Check if the character at the specified position is NUL. + */ + +#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset)) + +#define IS_Z(string) IS_Z_AT((string),0) + +/* + * Check if the character at the specified position is BOM. + */ + +#define IS_BOM_AT(string,offset) \ + (CHECK_AT((string),'\xEF',(offset)) \ + && CHECK_AT((string),'\xBB',(offset)+1) \ + && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */ + +#define IS_BOM(string) IS_BOM_AT(string,0) + +/* + * Check if the character at the specified position is space. + */ + +#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset)) + +#define IS_SPACE(string) IS_SPACE_AT((string),0) + +/* + * Check if the character at the specified position is tab. + */ + +#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset)) + +#define IS_TAB(string) IS_TAB_AT((string),0) + +/* + * Check if the character at the specified position is blank (space or tab). + */ + +#define IS_BLANK_AT(string,offset) \ + (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset))) + +#define IS_BLANK(string) IS_BLANK_AT((string),0) + +/* + * Check if the character at the specified position is a line break. + */ + +#define IS_BREAK_AT(string,offset) \ + (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \ + || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \ + || (CHECK_AT((string),'\xC2',(offset)) \ + && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \ + || (CHECK_AT((string),'\xE2',(offset)) \ + && CHECK_AT((string),'\x80',(offset)+1) \ + && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \ + || (CHECK_AT((string),'\xE2',(offset)) \ + && CHECK_AT((string),'\x80',(offset)+1) \ + && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */ + +#define IS_BREAK(string) IS_BREAK_AT((string),0) + +#define IS_CRLF_AT(string,offset) \ + (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1)) + +#define IS_CRLF(string) IS_CRLF_AT((string),0) + +/* + * Check if the character is a line break or NUL. + */ + +#define IS_BREAKZ_AT(string,offset) \ + (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset))) + +#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0) + +/* + * Check if the character is a line break, space, or NUL. + */ + +#define IS_SPACEZ_AT(string,offset) \ + (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) + +#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0) + +/* + * Check if the character is a line break, space, tab, or NUL. + */ + +#define IS_BLANKZ_AT(string,offset) \ + (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) + +#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0) + +/* + * Determine the width of the character. + */ + +#define WIDTH_AT(string,offset) \ + (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \ + ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \ + ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \ + ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0) + +#define WIDTH(string) WIDTH_AT((string),0) + +/* + * Move the string pointer to the next character. + */ + +#define MOVE(string) ((string).pointer += WIDTH((string))) + +/* + * Copy a character and move the pointers of both strings. + */ + +#define COPY(string_a,string_b) \ + ((*(string_b).pointer & 0x80) == 0x00 ? \ + (*((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xE0) == 0xC0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xF0) == 0xE0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xF8) == 0xF0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : 0) + +/* + * Stack and queue management. + */ + +YAML_DECLARE(int) +yaml_stack_extend(void **start, void **top, void **end); + +YAML_DECLARE(int) +yaml_queue_extend(void **start, void **head, void **tail, void **end); + +#define STACK_INIT(context,stack,size) \ + (((stack).start = yaml_malloc((size)*sizeof(*(stack).start))) ? \ + ((stack).top = (stack).start, \ + (stack).end = (stack).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define STACK_DEL(context,stack) \ + (yaml_free((stack).start), \ + (stack).start = (stack).top = (stack).end = 0) + +#define STACK_EMPTY(context,stack) \ + ((stack).start == (stack).top) + +#define STACK_LIMIT(context,stack,size) \ + ((stack).top - (stack).start < (size) ? \ + 1 : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define PUSH(context,stack,value) \ + (((stack).top != (stack).end \ + || yaml_stack_extend((void **)&(stack).start, \ + (void **)&(stack).top, (void **)&(stack).end)) ? \ + (*((stack).top++) = value, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define POP(context,stack) \ + (*(--(stack).top)) + +#define QUEUE_INIT(context,queue,size) \ + (((queue).start = yaml_malloc((size)*sizeof(*(queue).start))) ? \ + ((queue).head = (queue).tail = (queue).start, \ + (queue).end = (queue).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define QUEUE_DEL(context,queue) \ + (yaml_free((queue).start), \ + (queue).start = (queue).head = (queue).tail = (queue).end = 0) + +#define QUEUE_EMPTY(context,queue) \ + ((queue).head == (queue).tail) + +#define ENQUEUE(context,queue,value) \ + (((queue).tail != (queue).end \ + || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ + (void **)&(queue).tail, (void **)&(queue).end)) ? \ + (*((queue).tail++) = value, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define DEQUEUE(context,queue) \ + (*((queue).head++)) + +#define QUEUE_INSERT(context,queue,index,value) \ + (((queue).tail != (queue).end \ + || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ + (void **)&(queue).tail, (void **)&(queue).end)) ? \ + (memmove((queue).head+(index)+1,(queue).head+(index), \ + ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \ + *((queue).head+(index)) = value, \ + (queue).tail++, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +/* + * Token initializers. + */ + +#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \ + (memset(&(token), 0, sizeof(yaml_token_t)), \ + (token).type = (token_type), \ + (token).start_mark = (token_start_mark), \ + (token).end_mark = (token_end_mark)) + +#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \ + (token).data.stream_start.encoding = (token_encoding)) + +#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark))) + +#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \ + (token).data.alias.value = (token_value)) + +#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \ + (token).data.anchor.value = (token_value)) + +#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \ + (token).data.tag.handle = (token_handle), \ + (token).data.tag.suffix = (token_suffix)) + +#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \ + (token).data.scalar.value = (token_value), \ + (token).data.scalar.length = (token_length), \ + (token).data.scalar.style = (token_style)) + +#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ + (token).data.version_directive.major = (token_major), \ + (token).data.version_directive.minor = (token_minor)) + +#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ + (token).data.tag_directive.handle = (token_handle), \ + (token).data.tag_directive.prefix = (token_prefix)) + +/* + * Event initializers. + */ + +#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \ + (memset(&(event), 0, sizeof(yaml_event_t)), \ + (event).type = (event_type), \ + (event).start_mark = (event_start_mark), \ + (event).end_mark = (event_end_mark)) + +#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \ + (event).data.stream_start.encoding = (event_encoding)) + +#define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark))) + +#define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \ + event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \ + (event).data.document_start.version_directive = (event_version_directive), \ + (event).data.document_start.tag_directives.start = (event_tag_directives_start), \ + (event).data.document_start.tag_directives.end = (event_tag_directives_end), \ + (event).data.document_start.implicit = (event_implicit)) + +#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \ + (event).data.document_end.implicit = (event_implicit)) + +#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \ + (event).data.alias.anchor = (event_anchor)) + +#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \ + event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \ + (event).data.scalar.anchor = (event_anchor), \ + (event).data.scalar.tag = (event_tag), \ + (event).data.scalar.value = (event_value), \ + (event).data.scalar.length = (event_length), \ + (event).data.scalar.plain_implicit = (event_plain_implicit), \ + (event).data.scalar.quoted_implicit = (event_quoted_implicit), \ + (event).data.scalar.style = (event_style)) + +#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \ + event_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \ + (event).data.sequence_start.anchor = (event_anchor), \ + (event).data.sequence_start.tag = (event_tag), \ + (event).data.sequence_start.implicit = (event_implicit), \ + (event).data.sequence_start.style = (event_style)) + +#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark))) + +#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \ + event_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \ + (event).data.mapping_start.anchor = (event_anchor), \ + (event).data.mapping_start.tag = (event_tag), \ + (event).data.mapping_start.implicit = (event_implicit), \ + (event).data.mapping_start.style = (event_style)) + +#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark))) + +/* + * Document initializer. + */ + +#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \ + document_version_directive,document_tag_directives_start, \ + document_tag_directives_end,document_start_implicit, \ + document_end_implicit,document_start_mark,document_end_mark) \ + (memset(&(document), 0, sizeof(yaml_document_t)), \ + (document).nodes.start = (document_nodes_start), \ + (document).nodes.end = (document_nodes_end), \ + (document).nodes.top = (document_nodes_start), \ + (document).version_directive = (document_version_directive), \ + (document).tag_directives.start = (document_tag_directives_start), \ + (document).tag_directives.end = (document_tag_directives_end), \ + (document).start_implicit = (document_start_implicit), \ + (document).end_implicit = (document_end_implicit), \ + (document).start_mark = (document_start_mark), \ + (document).end_mark = (document_end_mark)) + +/* + * Node initializers. + */ + +#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \ + (memset(&(node), 0, sizeof(yaml_node_t)), \ + (node).type = (node_type), \ + (node).tag = (node_tag), \ + (node).start_mark = (node_start_mark), \ + (node).end_mark = (node_end_mark)) + +#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.scalar.value = (node_value), \ + (node).data.scalar.length = (node_length), \ + (node).data.scalar.style = (node_style)) + +#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.sequence.items.start = (node_items_start), \ + (node).data.sequence.items.end = (node_items_end), \ + (node).data.sequence.items.top = (node_items_start), \ + (node).data.sequence.style = (node_style)) + +#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.mapping.pairs.start = (node_pairs_start), \ + (node).data.mapping.pairs.end = (node_pairs_end), \ + (node).data.mapping.pairs.top = (node_pairs_start), \ + (node).data.mapping.style = (node_style)) + diff --git a/libyaml/win32/config.h b/libyaml/win32/config.h new file mode 100644 index 00000000..c5515513 --- /dev/null +++ b/libyaml/win32/config.h @@ -0,0 +1,4 @@ +#define YAML_VERSION_MAJOR 0 +#define YAML_VERSION_MINOR 1 +#define YAML_VERSION_PATCH 5 +#define YAML_VERSION_STRING "0.1.5" diff --git a/libyaml/win32/yaml2008.vcproj b/libyaml/win32/yaml2008.vcproj new file mode 100644 index 00000000..1842c712 --- /dev/null +++ b/libyaml/win32/yaml2008.vcproj @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libyaml/win32/yaml2013.vcxproj b/libyaml/win32/yaml2013.vcxproj new file mode 100644 index 00000000..5c510090 --- /dev/null +++ b/libyaml/win32/yaml2013.vcxproj @@ -0,0 +1,100 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + {0212E0DF-06DA-4080-BD1D-F3B01599F70F} + Win32Proj + yaml2013 + yaml + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;YAML_DECLARE_STATIC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + .;../include + MultiThreadedDebug + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;YAML_DECLARE_STATIC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + .;../include + MultiThreaded + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/libyaml/win32/yaml2013.vcxproj.filters b/libyaml/win32/yaml2013.vcxproj.filters new file mode 100644 index 00000000..2446a756 --- /dev/null +++ b/libyaml/win32/yaml2013.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file From 0cc6a4841f33581a2e7ea7c5a42dd0af11b1331e Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 21 Mar 2016 22:41:29 +0000 Subject: [PATCH 100/121] Add test/TestCPU6502 --- AppleWinExpress2013.sln | 26 +- ApplewinExpress9.00.sln | 16 +- test/TestCPU6502/TestCPU6502-vs2013.vcxproj | 89 ++ .../TestCPU6502-vs2013.vcxproj.filters | 22 + test/TestCPU6502/TestCPU6502.cpp | 1127 +++++++++++++++++ test/TestCPU6502/TestCPU6502.vcproj | 205 +++ test/TestCPU6502/stdafx.cpp | 8 + test/TestCPU6502/stdafx.h | 13 + 8 files changed, 1504 insertions(+), 2 deletions(-) create mode 100644 test/TestCPU6502/TestCPU6502-vs2013.vcxproj create mode 100644 test/TestCPU6502/TestCPU6502-vs2013.vcxproj.filters create mode 100644 test/TestCPU6502/TestCPU6502.cpp create mode 100644 test/TestCPU6502/TestCPU6502.vcproj create mode 100644 test/TestCPU6502/stdafx.cpp create mode 100644 test/TestCPU6502/stdafx.h diff --git a/AppleWinExpress2013.sln b/AppleWinExpress2013.sln index e4ea32bb..10dc5eb9 100644 --- a/AppleWinExpress2013.sln +++ b/AppleWinExpress2013.sln @@ -1,8 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2012 for Windows Desktop +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2013.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" ProjectSection(ProjectDependencies) = postProject + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} = {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} + {0212E0DF-06DA-4080-BD1D-F3B01599F70F} = {0212E0DF-06DA-4080-BD1D-F3B01599F70F} {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} = {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} EndProjectSection @@ -11,6 +15,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip_lib", "zip_lib\zip_lib2 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib-Express2013.vcxproj", "{9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2013.vcxproj", "{0212E0DF-06DA-4080-BD1D-F3B01599F70F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCPU6502", "test\TestCPU6502\TestCPU6502-vs2013.vcxproj", "{CF5A49BF-62A5-41BB-B10C-F34D556A7A45}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug NoDX|Win32 = Debug NoDX|Win32 @@ -43,6 +51,22 @@ Global {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release NoDX|Win32.Build.0 = Release|Win32 {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release|Win32.ActiveCfg = Release|Win32 {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release|Win32.Build.0 = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug|Win32.ActiveCfg = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug|Win32.Build.0 = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release NoDX|Win32.Build.0 = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release|Win32.ActiveCfg = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release|Win32.Build.0 = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug|Win32.Build.0 = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.Build.0 = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.ActiveCfg = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ApplewinExpress9.00.sln b/ApplewinExpress9.00.sln index 6fbec8fe..475784bc 100644 --- a/ApplewinExpress9.00.sln +++ b/ApplewinExpress9.00.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 +# Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Applewin", "ApplewinExpress9.00.vcproj", "{1DA0C491-B5F4-4EC8-B1D2-CF6BE635DADC}" ProjectSection(ProjectDependencies) = postProject + {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F} = {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F} {7935B998-C713-42AE-8F6D-9FF9080A1B1B} = {7935B998-C713-42AE-8F6D-9FF9080A1B1B} + {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2} = {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2} {709278B8-C583-4BD8-90DE-4E4F35A3BD8B} = {709278B8-C583-4BD8-90DE-4E4F35A3BD8B} EndProjectSection EndProject @@ -11,6 +13,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib-Express9. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip_lib", "zip_lib\zip_lib.vcproj", "{709278B8-C583-4BD8-90DE-4E4F35A3BD8B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCPU6502", "test\TestCPU6502\TestCPU6502.vcproj", "{2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2008.vcproj", "{5CE8051A-3F0C-4C39-B1C0-3338E48BA60F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -29,6 +35,14 @@ Global {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Debug|Win32.Build.0 = Debug|Win32 {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Release|Win32.ActiveCfg = Release|Win32 {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Release|Win32.Build.0 = Release|Win32 + {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2}.Debug|Win32.Build.0 = Debug|Win32 + {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2}.Release|Win32.ActiveCfg = Release|Win32 + {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2}.Release|Win32.Build.0 = Release|Win32 + {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F}.Debug|Win32.Build.0 = Debug|Win32 + {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F}.Release|Win32.ActiveCfg = Release|Win32 + {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/TestCPU6502/TestCPU6502-vs2013.vcxproj b/test/TestCPU6502/TestCPU6502-vs2013.vcxproj new file mode 100644 index 00000000..3e2fbeb3 --- /dev/null +++ b/test/TestCPU6502/TestCPU6502-vs2013.vcxproj @@ -0,0 +1,89 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} + Win32Proj + TestCPU6502vs2013 + TestCPU6502 + + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/test/TestCPU6502/TestCPU6502-vs2013.vcxproj.filters b/test/TestCPU6502/TestCPU6502-vs2013.vcxproj.filters new file mode 100644 index 00000000..71e4100b --- /dev/null +++ b/test/TestCPU6502/TestCPU6502-vs2013.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/test/TestCPU6502/TestCPU6502.cpp b/test/TestCPU6502/TestCPU6502.cpp new file mode 100644 index 00000000..df50fe55 --- /dev/null +++ b/test/TestCPU6502/TestCPU6502.cpp @@ -0,0 +1,1127 @@ +#include "stdafx.h" + +#include "../../source/Applewin.h" +#include "../../source/CPU.h" + +// From Applewin.cpp +enum AppMode_e g_nAppMode = MODE_RUNNING; + +// From Memory.cpp +LPBYTE memwrite[0x100]; // TODO: Init +LPBYTE mem = NULL; // TODO: Init +LPBYTE memdirty = NULL; // TODO: Init +iofunction IORead[256] = {0}; // TODO: Init +iofunction IOWrite[256] = {0}; // TODO: Init + +// From Debugger_Types.h + enum AddressingMode_e // ADDRESSING_MODES_e + { + AM_IMPLIED // Note: SetDebugBreakOnInvalid() assumes this order of first 4 entries + , AM_1 // Invalid 1 Byte + , AM_2 // Invalid 2 Bytes + , AM_3 // Invalid 3 Bytes + }; + +// From CPU.cpp +#define AF_SIGN 0x80 +#define AF_OVERFLOW 0x40 +#define AF_RESERVED 0x20 +#define AF_BREAK 0x10 +#define AF_DECIMAL 0x08 +#define AF_INTERRUPT 0x04 +#define AF_ZERO 0x02 +#define AF_CARRY 0x01 + +regsrec regs; + +static const int IRQ_CHECK_TIMEOUT = 128; +static signed int g_nIrqCheckTimeout = IRQ_CHECK_TIMEOUT; + +static eCpuType g_ActiveCPU = CPU_65C02; + +eCpuType GetActiveCpu(void) +{ + return g_ActiveCPU; +} + +static __forceinline int Fetch(BYTE& iOpcode, ULONG uExecutedCycles) +{ + iOpcode = *(mem+regs.pc); + regs.pc++; + return 1; +} + +#define INV IsDebugBreakOnInvalid(AM_1); +inline int IsDebugBreakOnInvalid( int iOpcodeType ) +{ + return 0; +} + +static __forceinline void DoIrqProfiling(DWORD uCycles) +{ +} + +static __forceinline void CheckInterruptSources(ULONG uExecutedCycles) +{ +} + +static __forceinline void NMI(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) +{ +} + +static __forceinline void IRQ(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) +{ +} + +void RequestDebugger() +{ +} + +// From Debug.h +inline int IsDebugBreakpointHit() +{ + return 0; +} + +// From Debug.cpp +int g_bDebugBreakpointHit = 0; + +// From z80.cpp +DWORD z80_mainloop(ULONG uTotalCycles, ULONG uExecutedCycles) +{ + return 0; +} + +// From NTSC.cpp +void NTSC_VideoUpdateCycles( long cycles6502 ) +{ +} + +//------------------------------------- + +#include "../../source/cpu/cpu_general.inl" +#include "../../source/cpu/cpu_instructions.inl" +#include "../../source/cpu/cpu6502.h" // MOS 6502 +#include "../../source/cpu/cpu65C02.h" // WDC 65C02 + +void init(void) +{ + mem = (LPBYTE)VirtualAlloc(NULL,64*1024,MEM_COMMIT,PAGE_READWRITE); + + for (UINT i=0; i<256; i++) + memwrite[i] = mem+i*256; + + memdirty = new BYTE[256]; +} + +void reset(void) +{ + regs.a = 0; + regs.x = 0; + regs.y = 0; + regs.pc = 0x300; + regs.sp = 0x1FF; + regs.ps = 0; + regs.bJammed = 0; +} + +//------------------------------------- + +int GH264_test(void) +{ + // No page-cross + reset(); + regs.pc = 0x300; + WORD abs = regs.pc+3; + WORD dst = abs+2; + mem[regs.pc+0] = 0x6c; // JMP (IND) + mem[regs.pc+1] = abs&0xff; + mem[regs.pc+2] = abs>>8; + mem[regs.pc+3] = dst&0xff; + mem[regs.pc+4] = dst>>8; + + DWORD cycles = Cpu6502(0); + if (cycles != 5) return 1; + if (regs.pc != dst) return 1; + + reset(); + cycles = Cpu65C02(0); + if (cycles != 6) return 1; + if (regs.pc != dst) return 1; + + // Page-cross + reset(); + regs.pc = 0x3fc; // 3FC: JMP (abs) + abs = regs.pc+3; // 3FF: lo(dst), hi(dst) + dst = abs+2; + mem[regs.pc+0] = 0x6c; // JMP (IND) + mem[regs.pc+1] = abs&0xff; + mem[regs.pc+2] = abs>>8; + mem[regs.pc+3] = dst&0xff; + mem[regs.pc+4] = mem[regs.pc & ~0xff] = dst>>8; // Allow for bug in 6502 + + cycles = Cpu6502(0); + if (cycles != 5) return 1; + if (regs.pc != dst) return 1; + + reset(); + regs.pc = 0x3fc; + mem[regs.pc & ~0xff] = 0; // Test that 65C02 fixes the bug in the 6502 + cycles = Cpu65C02(0); + if (cycles != 7) return 1; // todo: is this 6 or 7? + if (regs.pc != dst) return 1; + + return 0; +} + +//------------------------------------- + +void ASL_ABSX(BYTE x, WORD base, BYTE d) +{ + WORD addr = base+x; + mem[addr] = d; + + reset(); + regs.x = x; + mem[regs.pc+0] = 0x1e; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; +} + +void DEC_ABSX(BYTE x, WORD base, BYTE d) +{ + WORD addr = base+x; + mem[addr] = d; + + reset(); + regs.x = x; + mem[regs.pc+0] = 0xde; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; +} + +void INC_ABSX(BYTE x, WORD base, BYTE d) +{ + WORD addr = base+x; + mem[addr] = d; + + reset(); + regs.x = x; + mem[regs.pc+0] = 0xfe; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; +} + +int GH271_test(void) +{ + // asl abs,x + { + const WORD base = 0x20ff; + const BYTE d = 0x40; + + // no page-cross + { + const BYTE x = 0; + + ASL_ABSX(x, base, d); + if (Cpu6502(0) != 7) return 1; + if (mem[base+x] != ((d<<1)&0xff)) return 1; + + ASL_ABSX(x, base, d); + if (Cpu65C02(0) != 6) return 1; // Non-PX case is optimised on 65C02 + if (mem[base+x] != ((d<<1)&0xff)) return 1; + } + + // page-cross + { + const BYTE x = 1; + + ASL_ABSX(x, base, d); + if (Cpu6502(0) != 7) return 1; + if (mem[base+x] != ((d<<1)&0xff)) return 1; + + ASL_ABSX(x, base, d); + if (Cpu65C02(0) != 7) return 1; + if (mem[base+x] != ((d<<1)&0xff)) return 1; + } + } + + // dec abs,x + { + const WORD base = 0x20ff; + const BYTE d = 0x40; + + // no page-cross + { + const BYTE x = 0; + + DEC_ABSX(x, base, d); + if (Cpu6502(0) != 7) return 1; + if (mem[base+x] != ((d-1)&0xff)) return 1; + + DEC_ABSX(x, base, d); + if (Cpu65C02(0) != 7) return 1; // NB. Not optimised for 65C02 + if (mem[base+x] != ((d-1)&0xff)) return 1; + } + + // page-cross + { + const BYTE x = 1; + + DEC_ABSX(x, base, d); + if (Cpu6502(0) != 7) return 1; + if (mem[base+x] != ((d-1)&0xff)) return 1; + + DEC_ABSX(x, base, d); + if (Cpu65C02(0) != 7) return 1; + if (mem[base+x] != ((d-1)&0xff)) return 1; + } + } + + // inc abs,x + { + const WORD base = 0x20ff; + const BYTE d = 0x40; + + // no page-cross + { + const BYTE x = 0; + + INC_ABSX(x, base, d); + if (Cpu6502(0) != 7) return 1; + if (mem[base+x] != ((d+1)&0xff)) return 1; + + INC_ABSX(x, base, d); + if (Cpu65C02(0) != 7) return 1; // NB. Not optimised for 65C02 + if (mem[base+x] != ((d+1)&0xff)) return 1; + } + + // page-cross + { + const BYTE x = 1; + + INC_ABSX(x, base, d); + if (Cpu6502(0) != 7) return 1; + if (mem[base+x] != ((d+1)&0xff)) return 1; + + INC_ABSX(x, base, d); + if (Cpu65C02(0) != 7) return 1; + if (mem[base+x] != ((d+1)&0xff)) return 1; + } + } + + return 0; +} + +//------------------------------------- + +enum {CYC_6502=0, CYC_6502_PX, CYC_65C02, CYC_65C02_PX}; + +const BYTE g_OpcodeTimings[256][4] = +{ +// 6502 (no page-cross), 6502 (page-cross), 65C02 (no page-cross), 65C02 (page-cross) + {7,7,7,7}, // 00 + {6,6,6,6}, // 01 + {2,2,2,2}, // 02 + {8,8,1,1}, // 03 + {3,3,5,5}, // 04 + {3,3,3,3}, // 05 + {5,5,5,5}, // 06 + {5,5,1,1}, // 07 + {3,3,3,3}, // 08 + {2,2,2,2}, // 09 + {2,2,2,2}, // 0A + {2,2,1,1}, // 0B + {4,5,6,6}, // 0C + {4,4,4,4}, // 0D + {6,6,6,6}, // 0E + {6,6,1,1}, // 0F + {3,3,3,3}, // 10 + {5,6,5,6}, // 11 + {2,2,5,5}, // 12 + {8,8,1,1}, // 13 + {4,4,5,5}, // 14 + {4,4,4,4}, // 15 + {6,6,6,6}, // 16 + {6,6,1,1}, // 17 + {2,2,2,2}, // 18 + {4,5,4,5}, // 19 + {2,2,2,2}, // 1A + {7,7,1,1}, // 1B + {4,5,6,6}, // 1C + {4,5,4,5}, // 1D + {7,7,6,7}, // 1E + {7,7,1,1}, // 1F + {6,6,6,6}, // 20 + {6,6,6,6}, // 21 + {2,2,2,2}, // 22 + {8,8,1,1}, // 23 + {3,3,3,3}, // 24 + {3,3,3,3}, // 25 + {5,5,5,5}, // 26 + {5,5,1,1}, // 27 + {4,4,4,4}, // 28 + {2,2,2,2}, // 29 + {2,2,2,2}, // 2A + {2,2,1,1}, // 2B + {4,4,4,4}, // 2C + {4,4,4,4}, // 2D + {6,6,6,6}, // 2E + {6,6,1,1}, // 2F + {2,2,2,2}, // 30 + {5,6,5,6}, // 31 + {2,2,5,5}, // 32 + {8,8,1,1}, // 33 + {4,4,4,4}, // 34 + {4,4,4,4}, // 35 + {6,6,6,6}, // 36 + {6,6,1,1}, // 37 + {2,2,2,2}, // 38 + {4,5,4,5}, // 39 + {2,2,2,2}, // 3A + {7,7,1,1}, // 3B + {4,5,4,5}, // 3C + {4,5,4,5}, // 3D + {6,6,6,7}, // 3E + {7,7,1,1}, // 3F + {6,6,6,6}, // 40 + {6,6,6,6}, // 41 + {2,2,2,2}, // 42 + {8,8,1,1}, // 43 + {3,3,3,3}, // 44 + {3,3,3,3}, // 45 + {5,5,5,5}, // 46 + {5,5,1,1}, // 47 + {3,3,3,3}, // 48 + {2,2,2,2}, // 49 + {2,2,2,2}, // 4A + {2,2,1,1}, // 4B + {3,3,3,3}, // 4C + {4,4,4,4}, // 4D + {6,6,6,6}, // 4E + {6,6,1,1}, // 4F + {3,3,3,3}, // 50 + {5,6,5,6}, // 51 + {2,2,5,5}, // 52 + {8,8,1,1}, // 53 + {4,4,4,4}, // 54 + {4,4,4,4}, // 55 + {6,6,6,6}, // 56 + {6,6,1,1}, // 57 + {2,2,2,2}, // 58 + {4,5,4,5}, // 59 + {2,2,3,3}, // 5A + {7,7,1,1}, // 5B + {4,5,8,8}, // 5C + {4,5,4,5}, // 5D + {6,6,6,7}, // 5E + {7,7,1,1}, // 5F + {6,6,6,6}, // 60 + {6,6,6,6}, // 61 + {2,2,2,2}, // 62 + {8,8,1,1}, // 63 + {3,3,3,3}, // 64 + {3,3,3,3}, // 65 + {5,5,5,5}, // 66 + {5,5,1,1}, // 67 + {4,4,4,4}, // 68 + {2,2,2,2}, // 69 + {2,2,2,2}, // 6A + {2,2,1,1}, // 6B + {5,5,7,7}, // 6C + {4,4,4,4}, // 6D + {6,6,6,6}, // 6E + {6,6,1,1}, // 6F + {2,2,2,2}, // 70 + {5,6,5,6}, // 71 + {2,2,5,5}, // 72 + {8,8,1,1}, // 73 + {4,4,4,4}, // 74 + {4,4,4,4}, // 75 + {6,6,6,6}, // 76 + {6,6,1,1}, // 77 + {2,2,2,2}, // 78 + {4,5,4,5}, // 79 + {2,2,4,4}, // 7A + {7,7,1,1}, // 7B + {4,5,6,6}, // 7C + {4,5,4,5}, // 7D + {6,6,6,7}, // 7E + {7,7,1,1}, // 7F + {2,2,3,3}, // 80 + {6,6,6,6}, // 81 + {2,2,2,2}, // 82 + {6,6,1,1}, // 83 + {3,3,3,3}, // 84 + {3,3,3,3}, // 85 + {3,3,3,3}, // 86 + {3,3,1,1}, // 87 + {2,2,2,2}, // 88 + {2,2,2,2}, // 89 + {2,2,2,2}, // 8A + {2,2,1,1}, // 8B + {4,4,4,4}, // 8C + {4,4,4,4}, // 8D + {4,4,4,4}, // 8E + {4,4,1,1}, // 8F + {3,3,3,3}, // 90 + {6,6,6,6}, // 91 + {2,2,5,5}, // 92 + {6,6,1,1}, // 93 + {4,4,4,4}, // 94 + {4,4,4,4}, // 95 + {4,4,4,4}, // 96 + {4,4,1,1}, // 97 + {2,2,2,2}, // 98 + {5,5,5,5}, // 99 + {2,2,2,2}, // 9A + {5,5,1,1}, // 9B + {5,5,4,4}, // 9C + {5,5,5,5}, // 9D + {5,5,5,5}, // 9E + {5,5,1,1}, // 9F + {2,2,2,2}, // A0 + {6,6,6,6}, // A1 + {2,2,2,2}, // A2 + {6,6,1,1}, // A3 + {3,3,3,3}, // A4 + {3,3,3,3}, // A5 + {3,3,3,3}, // A6 + {3,3,1,1}, // A7 + {2,2,2,2}, // A8 + {2,2,2,2}, // A9 + {2,2,2,2}, // AA + {2,2,1,1}, // AB + {4,4,4,4}, // AC + {4,4,4,4}, // AD + {4,4,4,4}, // AE + {4,4,1,1}, // AF + {2,2,2,2}, // B0 + {5,6,5,6}, // B1 + {2,2,5,5}, // B2 + {5,6,1,1}, // B3 + {4,4,4,4}, // B4 + {4,4,4,4}, // B5 + {4,4,4,4}, // B6 + {4,4,1,1}, // B7 + {2,2,2,2}, // B8 + {4,5,4,5}, // B9 + {2,2,2,2}, // BA + {4,5,1,1}, // BB + {4,5,4,5}, // BC + {4,5,4,5}, // BD + {4,5,4,5}, // BE + {4,5,1,1}, // BF + {2,2,2,2}, // C0 + {6,6,6,6}, // C1 + {2,2,2,2}, // C2 + {8,8,1,1}, // C3 + {3,3,3,3}, // C4 + {3,3,3,3}, // C5 + {5,5,5,5}, // C6 + {5,5,1,1}, // C7 + {2,2,2,2}, // C8 + {2,2,2,2}, // C9 + {2,2,2,2}, // CA + {2,2,1,1}, // CB + {4,4,4,4}, // CC + {4,4,4,4}, // CD + {6,6,6,6}, // CE + {6,6,1,1}, // CF + {3,3,3,3}, // D0 + {5,6,5,6}, // D1 + {2,2,5,5}, // D2 + {8,8,1,1}, // D3 + {4,4,4,4}, // D4 + {4,4,4,4}, // D5 + {6,6,6,6}, // D6 + {6,6,1,1}, // D7 + {2,2,2,2}, // D8 + {4,5,4,5}, // D9 + {2,2,3,3}, // DA + {7,7,1,1}, // DB + {4,5,4,4}, // DC + {4,5,4,5}, // DD + {7,7,7,7}, // DE + {7,7,1,1}, // DF + {2,2,2,2}, // E0 + {6,6,6,6}, // E1 + {2,2,2,2}, // E2 + {8,8,1,1}, // E3 + {3,3,3,3}, // E4 + {3,3,3,3}, // E5 + {5,5,5,5}, // E6 + {5,5,1,1}, // E7 + {2,2,2,2}, // E8 + {2,2,2,2}, // E9 + {2,2,2,2}, // EA + {2,2,1,1}, // EB + {4,4,4,4}, // EC + {4,4,4,4}, // ED + {6,6,6,6}, // EE + {6,6,1,1}, // EF + {2,2,2,2}, // F0 + {5,6,5,6}, // F1 + {2,2,5,5}, // F2 + {8,8,1,1}, // F3 + {4,4,4,4}, // F4 + {4,4,4,4}, // F5 + {6,6,6,6}, // F6 + {6,6,1,1}, // F7 + {2,2,2,2}, // F8 + {4,5,4,5}, // F9 + {2,2,4,4}, // FA + {7,7,1,1}, // FB + {4,5,4,4}, // FC + {4,5,4,5}, // FD + {7,7,7,7}, // FE + {7,7,1,1}, // FF +}; + +int GH278_Bcc_Sub(BYTE op, BYTE ps_not_taken, BYTE ps_taken, WORD pc) +{ + mem[pc+0] = op; + mem[pc+1] = 0x01; + const WORD dst_not_taken = pc+2; + const WORD dst_taken = pc+2 + mem[pc+1]; + + const int pagecross = (((pc+2) ^ dst_taken) >> 8) & 1; + + // 6502 + + reset(); + regs.pc = pc; + regs.ps = ps_not_taken; + if (Cpu6502(0) != 2) return 1; + if (regs.pc != dst_not_taken) return 1; + + reset(); + regs.pc = pc; + regs.ps = ps_taken; + if (Cpu6502(0) != 3+pagecross) return 1; + if (regs.pc != dst_taken) return 1; + + // 65C02 + + reset(); + regs.pc = pc; + regs.ps = ps_not_taken; + if (Cpu65C02(0) != 2) return 1; + if (regs.pc != dst_not_taken) return 1; + + reset(); + regs.pc = pc; + regs.ps = ps_taken; + if (Cpu65C02(0) != 3+pagecross) return 1; + if (regs.pc != dst_taken) return 1; + + return 0; +} + +int GH278_Bcc(BYTE op, BYTE ps_not_taken, BYTE ps_taken) +{ + if (GH278_Bcc_Sub(op, ps_not_taken, ps_taken, 0x300)) return 1; // no page cross + if (GH278_Bcc_Sub(op, ps_not_taken, ps_taken, 0x3FD)) return 1; // page cross + + return 0; +} + +int GH278_BRA(void) +{ + // No page-cross + { + WORD pc = 0x300; + mem[pc+0] = 0x80; // BRA + mem[pc+1] = 0x01; + const WORD dst_taken = pc+2 + mem[pc+1]; + + reset(); + regs.pc = pc; + if (Cpu65C02(0) != 3) return 1; + if (regs.pc != dst_taken) return 1; + } + + // Page-cross + { + WORD pc = 0x3FD; + mem[pc+0] = 0x80; // BRA + mem[pc+1] = 0x01; + const WORD dst_taken = pc+2 + mem[pc+1]; + + reset(); + regs.pc = pc; + if (Cpu65C02(0) != 4) return 1; + if (regs.pc != dst_taken) return 1; + } + + return 0; +} + +int GH278_JMP_INDX(void) +{ + // No page-cross + reset(); + regs.pc = 0x300; + WORD abs = regs.pc+3; + WORD dst = abs+2; + mem[regs.pc+0] = 0x7c; // JMP (IND,X) + mem[regs.pc+1] = abs&0xff; + mem[regs.pc+2] = abs>>8; + mem[regs.pc+3] = dst&0xff; + mem[regs.pc+4] = dst>>8; + + DWORD cycles = Cpu65C02(0); + if (cycles != 6) return 1; + if (regs.pc != dst) return 1; + + // Page-cross (case 1) + reset(); + regs.pc = 0x3fc; + abs = regs.pc+3; + dst = abs+2; + mem[regs.pc+0] = 0x7c; // JMP (IND,X) + mem[regs.pc+1] = abs&0xff; + mem[regs.pc+2] = abs>>8; + mem[regs.pc+3] = dst&0xff; + mem[regs.pc+4] = dst>>8; + + cycles = Cpu65C02(0); + if (cycles != 6) return 1; // todo: is this 6 or 7? + if (regs.pc != dst) return 1; + + // Page-cross (case 2) + reset(); + regs.x = 1; + regs.pc = 0x3fa; + abs = regs.pc+3; + dst = abs+2 + regs.x; + mem[regs.pc+0] = 0x7c; // JMP (IND,X) + mem[regs.pc+1] = abs&0xff; + mem[regs.pc+2] = abs>>8; + mem[regs.pc+3] = 0xcc; // unused + mem[regs.pc+4] = dst&0xff; + mem[regs.pc+5] = dst>>8; + + cycles = Cpu65C02(0); + if (cycles != 6) return 1; // todo: is this 6 or 7? + if (regs.pc != dst) return 1; + + return 0; +} + +int GH278_ADC_SBC(UINT op) +{ + const WORD base = 0x20ff; + reset(); + mem[regs.pc+0] = op; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + mem[0xff] = 0xff; mem[0x00] = 0x00; // For: OPCODE (zp),Y + + // No page-cross + reset(); + regs.ps = AF_DECIMAL; + DWORD cycles = Cpu6502(0); + if (g_OpcodeTimings[op][CYC_6502] != cycles) return 1; + + reset(); + regs.ps = AF_DECIMAL; + cycles = Cpu65C02(0); + if (g_OpcodeTimings[op][CYC_65C02]+1 != cycles) return 1; // CMOS is +1 cycles in decimal mode + + // Page-cross + reset(); + regs.ps = AF_DECIMAL; + regs.x = 1; + regs.y = 1; + cycles = Cpu6502(0); + if (g_OpcodeTimings[op][CYC_6502_PX] != cycles) return 1; + + reset(); + regs.ps = AF_DECIMAL; + regs.x = 1; + regs.y = 1; + cycles = Cpu65C02(0); + if (g_OpcodeTimings[op][CYC_65C02_PX]+1 != cycles) return 1; // CMOS is +1 cycles in decimal mode + + return 0; +} + +int GH278_ADC(void) +{ + const BYTE adc[] = {0x61,0x65,0x69,0x6D,0x71,0x72,0x75,0x79,0x7D}; + + for (UINT i = 0; i>8; + DWORD cycles = Cpu6502(0); + if (g_OpcodeTimings[op][variant] != cycles) return 1; + } + + variant++; + + // Page-cross + for (UINT op=0; op<256; op++) + { + reset(); + regs.x = 1; + regs.y = 1; + WORD base = 0x20ff; + mem[regs.pc+0] = op; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + mem[0xff] = 0xff; mem[0x00] = 0x00; // For: OPCODE (zp),Y + DWORD cycles = Cpu6502(0); + if (g_OpcodeTimings[op][variant] != cycles) return 1; + } + + variant++; + + // + // 65C02 + // + + // No page-cross + for (UINT op=0; op<256; op++) + { + reset(); + WORD base = 0x20ff; + mem[regs.pc+0] = op; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + DWORD cycles = Cpu65C02(0); + if (g_OpcodeTimings[op][variant] != cycles) return 1; + } + + variant++; + + // Page-cross + for (UINT op=0; op<256; op++) + { + reset(); + regs.x = 1; + regs.y = 1; + WORD base = 0x20ff; + mem[regs.pc+0] = op; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + mem[0xff] = 0xff; mem[0x00] = 0x00; // For: OPCODE (zp),Y + DWORD cycles = Cpu65C02(0); + if (g_OpcodeTimings[op][variant] != cycles) return 1; + } + + // + // Bcc + // + + if (GH278_Bcc(0x10, AF_SIGN, 0)) return 1; // BPL + if (GH278_Bcc(0x30, 0, AF_SIGN)) return 1; // BMI + if (GH278_Bcc(0x50, AF_OVERFLOW, 0)) return 1; // BVC + if (GH278_Bcc(0x70, 0, AF_OVERFLOW)) return 1; // BVS + if (GH278_Bcc(0x90, AF_CARRY, 0)) return 1; // BCC + if (GH278_Bcc(0xB0, 0, AF_CARRY)) return 1; // BCS + if (GH278_Bcc(0xD0, AF_ZERO, 0)) return 1; // BNE + if (GH278_Bcc(0xF0, 0, AF_ZERO)) return 1; // BEQ + if (GH278_BRA()) return 1; // BRA + + // + // JMP (IND) and JMP (IND,X) + // . NB. GH264_test() tests JMP (IND) + // + + if (GH278_JMP_INDX()) return 1; + + // + // ADC/SBC CMOS decimal mode is +1 cycles + // + + if (GH278_ADC()) return 1; + if (GH278_SBC()) return 1; + + return 0; +} + +//------------------------------------- + +DWORD AXA_ZPY(BYTE a, BYTE x, BYTE y, WORD base) +{ + reset(); + mem[0xfe] = base&0xff; + mem[0xff] = base>>8; + regs.a = a; + regs.x = x; + regs.y = y; + mem[regs.pc+0] = 0x93; + mem[regs.pc+1] = 0xfe; + return Cpu6502(0); +} + +DWORD AXA_ABSY(BYTE a, BYTE x, BYTE y, WORD base) +{ + reset(); + regs.a = a; + regs.x = x; + regs.y = y; + mem[regs.pc+0] = 0x9f; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + return Cpu6502(0); +} + +DWORD SAY_ABSX(BYTE a, BYTE x, BYTE y, WORD base) +{ + reset(); + regs.a = a; + regs.x = x; + regs.y = y; + mem[regs.pc+0] = 0x9c; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + return Cpu6502(0); +} + +DWORD TAS_ABSY(BYTE a, BYTE x, BYTE y, WORD base) +{ + reset(); + regs.a = a; + regs.x = x; + regs.y = y; + mem[regs.pc+0] = 0x9b; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + return Cpu6502(0); +} + +DWORD XAS_ABSY(BYTE a, BYTE x, BYTE y, WORD base) +{ + reset(); + regs.a = a; + regs.x = x; + regs.y = y; + mem[regs.pc+0] = 0x9e; + mem[regs.pc+1] = base&0xff; + mem[regs.pc+2] = base>>8; + return Cpu6502(0); +} + +int GH282_test(void) +{ + // axa (zp),y + { + WORD base = 0x20ff, addr = 0x20ff; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0xff, y = 0; + DWORD cycles = AXA_ZPY(a, x, y, base); + if (cycles != 6) return 1; + if (mem[addr] != (a & x & ((base>>8)+1))) return 1; + } + + // axa (zp),y (page-cross) + { + WORD base = 0x20ff, addr = 0x2000; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0xff, y = 1; + DWORD cycles = AXA_ZPY(a, x, y, base); + if (cycles != 6) return 1; + if (mem[addr] != (a & x & ((base>>8)+1))) return 1; + } + + // + + // axa abs,y + { + WORD base = 0x20ff, addr = 0x20ff; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0xff, y = 0; + DWORD cycles = AXA_ABSY(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (a & x & ((base>>8)+1))) return 1; + } + + // axa abs,y (page-cross) + { + WORD base = 0x20ff, addr = 0x2000; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0xff, y = 1; + DWORD cycles = AXA_ABSY(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (a & x & ((base>>8)+1))) return 1; + } + + // + + // say abs,x + { + WORD base = 0x20ff, addr = 0x20ff; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0, y=0x20; + DWORD cycles = SAY_ABSX(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (y & ((base>>8)+1))) return 1; + } + + // say abs,x (page-cross) + { + WORD base = 0x20ff, addr = 0x2000; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 1, y=0x20; + DWORD cycles = SAY_ABSX(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (y & ((base>>8)+1))) return 1; + } + + // + + // tas abs,y + { + WORD base = 0x20ff, addr = 0x20ff; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0xff, y = 0; + DWORD cycles = TAS_ABSY(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (a & x & ((base>>8)+1))) return 1; + if (regs.sp != (0x100 | (a & x))) return 1; + } + + // tas abs,y (page-cross) + { + WORD base = 0x20ff, addr = 0x2000; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0xff, y = 1; + DWORD cycles = TAS_ABSY(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (a & x & ((base>>8)+1))) return 1; + if (regs.sp != (0x100 | (a & x))) return 1; + } + + // + + // xas abs,y + { + WORD base = 0x20ff, addr = 0x20ff; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0x20, y = 0; + DWORD cycles = XAS_ABSY(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (x & ((base>>8)+1))) return 1; + } + + // xas abs,y (page-cross) + { + WORD base = 0x20ff, addr = 0x2000; + mem[addr] = 0xcc; + BYTE a = 0xea, x = 0x20, y = 1; + DWORD cycles = XAS_ABSY(a, x, y, base); + if (cycles != 5) return 1; + if (mem[addr] != (x & ((base>>8)+1))) return 1; + } + + return 0; +} + +//------------------------------------- + +int g_fn_C000_count = 0; + +BYTE __stdcall fn_C000(WORD, WORD, BYTE, BYTE, ULONG) +{ + g_fn_C000_count++; + return 42; +} + +int GH292_test(void) +{ + // Undocumented 65C02 NOPs: 1 cycle & 1 byte + for (UINT op=0; op<256; op+=0x10) + { + reset(); + WORD base=regs.pc; + + mem[regs.pc] = op+0x03; if (Cpu65C02(0) != 1 || regs.pc != base+1) return 1; + mem[regs.pc] = op+0x07; if (Cpu65C02(0) != 1 || regs.pc != base+2) return 1; + mem[regs.pc] = op+0x0B; if (Cpu65C02(0) != 1 || regs.pc != base+3) return 1; + mem[regs.pc] = op+0x0F; if (Cpu65C02(0) != 1 || regs.pc != base+4) return 1; + } + + // + + // Undocumented 65C02 NOP: LDD - LoaD and Discard + IORead[0] = fn_C000; + + reset(); + WORD base = regs.pc; + mem[regs.pc+0] = 0xDC; + mem[regs.pc+1] = 0x00; + mem[regs.pc+2] = 0xC0; + if (Cpu65C02(0) != 4 || regs.pc != base+3 || g_fn_C000_count != 1 || regs.a != 0) return 1; + + reset(); + base = regs.pc; + mem[regs.pc+0] = 0xFC; + mem[regs.pc+1] = 0x00; + mem[regs.pc+2] = 0xC0; + if (Cpu65C02(0) != 4 || regs.pc != base+3 || g_fn_C000_count != 2 || regs.a != 0) return 1; + + IORead[0] = NULL; + + return 0; +} + +//------------------------------------- + +int _tmain(int argc, _TCHAR* argv[]) +{ + int res = 1; + init(); + reset(); + + res = GH264_test(); + if (res) return res; + + res = GH271_test(); + if (res) return res; + + res = GH278_test(); + if (res) return res; + + res = GH282_test(); + if (res) return res; + + res = GH292_test(); + if (res) return res; + + return 0; +} diff --git a/test/TestCPU6502/TestCPU6502.vcproj b/test/TestCPU6502/TestCPU6502.vcproj new file mode 100644 index 00000000..f5582875 --- /dev/null +++ b/test/TestCPU6502/TestCPU6502.vcproj @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/TestCPU6502/stdafx.cpp b/test/TestCPU6502/stdafx.cpp new file mode 100644 index 00000000..eb380001 --- /dev/null +++ b/test/TestCPU6502/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// TestCPU6502.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/test/TestCPU6502/stdafx.h b/test/TestCPU6502/stdafx.h new file mode 100644 index 00000000..47956f7e --- /dev/null +++ b/test/TestCPU6502/stdafx.h @@ -0,0 +1,13 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include +#include + +#include + +#include From e98de27039ce54a340127ea3c329b4e04e58351b Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 21 Mar 2016 23:48:02 +0000 Subject: [PATCH 101/121] Manual merge from master @ c798157 --- AppleWinExpress2013.vcxproj | 58 +- AppleWinExpress2013.vcxproj.filters | 34 +- ApplewinExpress9.00.vcproj | 48 +- Disks/SAM Slot 5.dsk | Bin 0 -> 143360 bytes bin/History.txt | 6 + resource/Applewin.rc | 7 +- resource/resource.h | 63 +- source/6821.h | 41 +- source/AY8910.cpp | 223 ++++- source/AY8910.h | 6 + source/Applewin.cpp | 185 ++-- source/Applewin.h | 13 +- source/CPU.cpp | 147 +++- source/CPU.h | 19 +- source/CPU/cpu6502.h | 526 ++++++------ source/CPU/cpu65C02.h | 517 ++++++----- source/CPU/cpu65d02.h | 849 +++++++------------ source/CPU/cpu_general.inl | 57 +- source/CPU/cpu_instructions.inl | 113 ++- source/Common.h | 3 +- source/Configuration/Config.h | 9 +- source/Configuration/IPropertySheet.h | 3 + source/Configuration/PageAdvanced.cpp | 1 - source/Configuration/PageConfig.cpp | 1 + source/Configuration/PageInput.cpp | 12 +- source/Configuration/PageSound.cpp | 39 +- source/Configuration/PropertySheet.h | 4 + source/Configuration/PropertySheetHelper.cpp | 132 ++- source/Configuration/PropertySheetHelper.h | 4 +- source/Debugger/Debug.cpp | 27 +- source/Debugger/Debug.h | 2 +- source/Debugger/Debugger_Assembler.cpp | 1 - source/Debugger/Debugger_Commands.cpp | 769 +++++++++-------- source/Debugger/Debugger_Console.cpp | 3 +- source/Debugger/Debugger_Display.cpp | 6 +- source/Debugger/Debugger_Help.cpp | 28 +- source/Disk.cpp | 636 ++++++++------ source/Disk.h | 9 +- source/DiskImage.cpp | 123 ++- source/DiskImage.h | 13 +- source/DiskImageHelper.cpp | 10 +- source/Frame.cpp | 47 +- source/Frame.h | 1 + source/Harddisk.cpp | 444 +++++++--- source/Harddisk.h | 10 +- source/Joystick.cpp | 70 +- source/Joystick.h | 9 +- source/Keyboard.cpp | 52 +- source/Keyboard.h | 6 +- source/Log.cpp | 20 +- source/Memory.cpp | 369 ++++++-- source/Memory.h | 12 +- source/Mockingboard.cpp | 436 +++++++++- source/Mockingboard.h | 12 +- source/MouseInterface.cpp | 175 +++- source/MouseInterface.h | 22 +- source/NTSC.cpp | 16 +- source/NTSC.h | 2 +- source/ParallelPrinter.cpp | 82 +- source/ParallelPrinter.h | 7 +- source/Pravets.cpp | 48 ++ source/Pravets.h | 7 + source/SAM.cpp | 93 ++ source/SAM.h | 3 + source/SaveState.cpp | 556 +++++++++--- source/SaveState_Structs_common.h | 136 +++ source/SaveState_Structs_v1.h | 147 ++++ source/SerialComms.cpp | 153 +++- source/SerialComms.h | 9 +- source/Speaker.cpp | 68 +- source/Speaker.h | 12 +- source/StdAfx.h | 5 +- source/Structs.h | 285 ------- source/Tape.cpp | 6 +- source/Video.cpp | 53 +- source/Video.h | 14 +- source/YamlHelper.cpp | 482 +++++++++++ source/YamlHelper.h | 266 ++++++ source/Z80VICE/z80.cpp | 149 +++- source/Z80VICE/z80regs.h | 2 + source/z80emu.cpp | 3 +- source/z80emu.h | 5 + 82 files changed, 6133 insertions(+), 2908 deletions(-) create mode 100644 Disks/SAM Slot 5.dsk create mode 100644 source/Pravets.cpp create mode 100644 source/Pravets.h create mode 100644 source/SAM.cpp create mode 100644 source/SAM.h create mode 100644 source/SaveState_Structs_common.h create mode 100644 source/SaveState_Structs_v1.h delete mode 100644 source/Structs.h create mode 100644 source/YamlHelper.cpp create mode 100644 source/YamlHelper.h diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj index 95b86697..6d0c6dba 100644 --- a/AppleWinExpress2013.vcxproj +++ b/AppleWinExpress2013.vcxproj @@ -76,16 +76,19 @@ + + + + - @@ -97,6 +100,7 @@ + @@ -107,7 +111,7 @@ - + @@ -126,6 +130,7 @@ + @@ -152,6 +157,7 @@ + @@ -191,6 +197,7 @@ NotUsing + NotUsing @@ -237,6 +244,9 @@ {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} + + {0212e0df-06da-4080-bd1d-f3b01599f70f} +
@@ -343,9 +353,9 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreadedDebug
@@ -354,15 +364,22 @@ htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Debug\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreadedDebug @@ -371,6 +388,13 @@ htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Debug\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + @@ -379,9 +403,9 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreaded Speed @@ -394,6 +418,13 @@ UseLinkTimeCodeGeneration "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Release\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + @@ -402,9 +433,9 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreaded Speed @@ -417,6 +448,13 @@ UseLinkTimeCodeGeneration "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Release\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters index 6b8315a3..c9b778eb 100644 --- a/AppleWinExpress2013.vcxproj.filters +++ b/AppleWinExpress2013.vcxproj.filters @@ -172,6 +172,15 @@ Source Files\Video + + Source Files\Model + + + Source Files\Emulator + + + Source Files\Emulator + @@ -372,9 +381,6 @@ Source Files - - Source Files\_Headers - Source Files\Emulator @@ -423,6 +429,21 @@ Source Files\Video + + Source Files\Model + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\_Headers + + + Source Files\_Headers + @@ -591,9 +612,6 @@ Docs - - Docs - Docs @@ -603,6 +621,7 @@ Docs + @@ -644,6 +663,9 @@ {b5c6889e-727d-4339-96c8-e4284e1d6e0f} + + {15b450e4-f89f-4d80-9c44-48b32f33f3e3} + diff --git a/ApplewinExpress9.00.vcproj b/ApplewinExpress9.00.vcproj index 27e7e9f1..5542a063 100644 --- a/ApplewinExpress9.00.vcproj +++ b/ApplewinExpress9.00.vcproj @@ -26,6 +26,8 @@ > + + + + @@ -734,6 +746,14 @@ RelativePath=".\source\Tape.h" > + + + + @@ -755,11 +775,15 @@ > + + @@ -959,6 +983,18 @@ > + + + + + + 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 NARrJB2&^IS{{hSgBl`dV literal 0 HcmV?d00001 diff --git a/bin/History.txt b/bin/History.txt index 83fd4e47..5b9a6ed3 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -9,6 +9,12 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.25.0.4 - 23 Apr 2015 +---------------------- +Fixes: +. [Bug #276] -d1 command line argument caused AppleWin to quickly exit. + + 1.25.0.3 - 8 Sep 2014 --------------------- Note: This is the last planned version to support Win98/ME. diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 172da881..2ba7acc2 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -154,10 +154,11 @@ BEGIN CONTROL "Slider1",IDC_SPKR_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,13,47,28,60 LTEXT "&Mockingboard:",IDC_STATIC,49,39,51,8 CONTROL "Slider1",IDC_MB_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,59,47,25,60 - GROUPBOX "Sound Cards",IDC_STATIC,6,122,197,61 + GROUPBOX "Sound Cards",IDC_STATIC,6,122,197,64 CONTROL "Mockingboards (in slots 4 && 5)",IDC_MB_ENABLE,"Button",BS_AUTORADIOBUTTON,10,136,142,8 CONTROL "Phasor (in slot 4)",IDC_PHASOR_ENABLE,"Button",BS_AUTORADIOBUTTON,10,149,92,10 - CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,163,78,10 + CONTROL "SAM/DAC (in slot 5)",IDC_SAM_ENABLE,"Button",BS_AUTORADIOBUTTON,10,162,95,10 + CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,175,78,10 END IDD_PROPPAGE_DISK DIALOGEX 0, 0, 211, 188 @@ -270,7 +271,7 @@ BEGIN VALUE "FileDescription", "Apple //e Emulator for Windows" VALUE "FileVersion", "1.26.0.0" VALUE "InternalName", "APPLEWIN" - VALUE "LegalCopyright", " 1994-2014 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis" + VALUE "LegalCopyright", " 1994-2015 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis" VALUE "OriginalFilename", "APPLEWIN.EXE" VALUE "ProductName", "Apple //e Emulator" VALUE "ProductVersion", "1.26.0.0 Alpha" diff --git a/resource/resource.h b/resource/resource.h index 97d23fcc..651ce3ce 100644 --- a/resource/resource.h +++ b/resource/resource.h @@ -67,36 +67,39 @@ #define IDC_SPIN_XTRIM 1026 #define IDC_SPIN_YTRIM 1027 #define IDC_PHASOR_ENABLE 1029 -#define IDC_SOUNDCARD_DISABLE 1030 -#define IDC_TFE_SETTINGS_ENABLE_T 1031 -#define IDC_TFE_SETTINGS_ENABLE 1032 -#define IDC_TFE_SETTINGS_INTERFACE_T 1033 -#define IDC_TFE_SETTINGS_INTERFACE 1034 -#define IDC_TFE_SETTINGS_INTERFACE_NAME 1035 -#define IDC_TFE_SETTINGS_INTERFACE_DESC 1036 -#define IDS_TFE_CAPTION 1037 -#define IDS_TFE_ETHERNET 1038 -#define IDS_TFE_INTERFACE 1039 -#define IDS_OK 1040 -#define IDS_CANCEL 1041 -#define IDC_ETHERNET 1042 -#define IDC_SCROLLLOCK_TOGGLE 1043 -#define IDC_MOUSE_IN_SLOT4 1044 -#define IDC_THE_FREEZES_F8_ROM_FW 1045 -#define IDC_MOUSE_CROSSHAIR 1046 -#define IDC_CLONETYPE 1047 -#define IDC_MOUSE_RESTRICT_TO_WINDOW 1048 -#define IDC_CIDERPRESS_BROWSE 1049 -#define IDC_CIDERPRESS_FILENAME 1050 -#define IDC_CPM_CONFIG 1051 -#define IDC_DUMPTOPRINTER 1052 -#define IDC_PRINTER_DUMP_FILENAME 1053 -#define IDC_PRINTER_DUMP_FILENAME_BROWSE 1054 -#define IDC_PRINTER_CONVERT_ENCODING 1055 -#define IDC_PRINTER_FILTER_UNPRINTABLE 1056 -#define IDC_PRINTER_APPEND 1057 -#define IDC_SPIN_PRINTER_IDLE 1058 -#define IDC_CHECK_HALF_SCAN_LINES 1059 +#define IDC_SAM_ENABLE 1030 +#define IDC_SOUNDCARD_DISABLE 1031 + +#define IDC_TFE_SETTINGS_ENABLE_T 1032 +#define IDC_TFE_SETTINGS_ENABLE 1033 +#define IDC_TFE_SETTINGS_INTERFACE_T 1034 +#define IDC_TFE_SETTINGS_INTERFACE 1035 +#define IDC_TFE_SETTINGS_INTERFACE_NAME 1036 +#define IDC_TFE_SETTINGS_INTERFACE_DESC 1037 +#define IDS_TFE_CAPTION 1038 +#define IDS_TFE_ETHERNET 1039 +#define IDS_TFE_INTERFACE 1040 +#define IDS_OK 1041 +#define IDS_CANCEL 1042 +#define IDC_ETHERNET 1043 +#define IDC_SCROLLLOCK_TOGGLE 1044 +#define IDC_MOUSE_IN_SLOT4 1045 +#define IDC_THE_FREEZES_F8_ROM_FW 1046 +#define IDC_MOUSE_CROSSHAIR 1047 +#define IDC_CLONETYPE 1048 +#define IDC_MOUSE_RESTRICT_TO_WINDOW 1049 +#define IDC_CIDERPRESS_BROWSE 1050 +#define IDC_CIDERPRESS_FILENAME 1051 +#define IDC_CPM_CONFIG 1052 +#define IDC_DUMPTOPRINTER 1053 +#define IDC_PRINTER_DUMP_FILENAME 1054 +#define IDC_PRINTER_DUMP_FILENAME_BROWSE 1055 +#define IDC_PRINTER_CONVERT_ENCODING 1056 +#define IDC_PRINTER_FILTER_UNPRINTABLE 1057 +#define IDC_PRINTER_APPEND 1058 +#define IDC_SPIN_PRINTER_IDLE 1059 + +#define IDC_CHECK_HALF_SCAN_LINES 1060 #define IDC_GPL_TEXT 1061 #define IDC_GPL_BORDER 1063 #define IDC_APPLEWIN_VERSION 1064 diff --git a/source/6821.h b/source/6821.h index fb92378a..5b269581 100644 --- a/source/6821.h +++ b/source/6821.h @@ -32,6 +32,21 @@ typedef struct mem_write_handler func; } STWriteHandler; +struct mc6821_s { + /* MC6821 register. */ + BYTE pra; + BYTE ddra; + BYTE cra; + BYTE prb; + BYTE ddrb; + BYTE crb; + + /* Drive structure */ +// struct drive_s *drive; +}; +typedef struct mc6821_s mc6821_t; + + class C6821 { public: @@ -64,6 +79,18 @@ public: m_stOutB.objTo = objTo; m_stOutB.func = func; } + void Get6821(mc6821_t& r6821, BYTE& byIA, BYTE& byIB) + { + r6821 = mc6821[0]; + byIA = m_byIA; + byIB = m_byIB; + } + void Set6821(const mc6821_t& r6821, const BYTE byIA, const BYTE byIB) + { + mc6821[0] = r6821; + m_byIA = byIA; + m_byIB = byIB; + } // AppleWin:TC END private: @@ -75,20 +102,6 @@ private: //struct drive_s; - struct mc6821_s { - /* MC6821 register. */ - BYTE pra; - BYTE ddra; - BYTE cra; - BYTE prb; - BYTE ddrb; - BYTE crb; - - /* Drive structure */ - // struct drive_s *drive; - }; - typedef struct mc6821_s mc6821_t; - //struct drive_context_s; void mc6821_init(/*struct drive_context_s *drv*/); void mc6821_reset(/*struct drive_context_s *drv*/); diff --git a/source/AY8910.cpp b/source/AY8910.cpp index 7600740e..e742e407 100644 --- a/source/AY8910.cpp +++ b/source/AY8910.cpp @@ -33,6 +33,7 @@ #include "Applewin.h" // For g_fh #include "Mockingboard.h" // For g_uTimer1IrqCount +#include "YamlHelper.h" /* The AY white noise RNG algorithm is based on info from MAME's ay8910.c - * MAME's licence explicitly permits free use of info (even encourages it). @@ -114,12 +115,17 @@ static int rstereopos, rchan1pos, rchan2pos, rchan3pos; double CAY8910::m_fCurrentCLK_AY8910 = 0.0; -CAY8910::CAY8910() : - // Init the statics that were in sound_ay_overlay() - rng(1), - noise_toggle(0), - env_first(1), env_rev(0), env_counter(15) +void CAY8910::init(void) { + // Init the statics that were in sound_ay_overlay() + rng = 1; + noise_toggle = 0; + env_first = 1; env_rev = 0; env_counter = 15; +} + +CAY8910::CAY8910(void) +{ + init(); m_fCurrentCLK_AY8910 = g_fCurrentCLK6502; }; @@ -731,6 +737,8 @@ void CAY8910::sound_ay_reset( void ) { int f; + init(); // AppleWin:TC + /* recalculate timings based on new machines ay clock */ sound_ay_init(); @@ -940,6 +948,192 @@ sound_beeper( int is_tape, int on ) } #endif +// + +#define SS_YAML_KEY_AY8910 "AY8910" + +#define SS_YAML_KEY_TONE0_TICK "Tone0 Tick" +#define SS_YAML_KEY_TONE1_TICK "Tone1 Tick" +#define SS_YAML_KEY_TONE2_TICK "Tone2 Tick" +#define SS_YAML_KEY_TONE0_HIGH "Tone0 High" +#define SS_YAML_KEY_TONE1_HIGH "Tone1 High" +#define SS_YAML_KEY_TONE2_HIGH "Tone2 High" +#define SS_YAML_KEY_NOISE_TICK "Noise Tick" +#define SS_YAML_KEY_TONE_SUBCYCLES "Tone Subcycles" +#define SS_YAML_KEY_ENV_SUBCYCLES "Env Subcycles" +#define SS_YAML_KEY_ENV_INTERNAL_TICK "Env Internal Tick" +#define SS_YAML_KEY_ENV_TICK "Env Tick" +#define SS_YAML_KEY_TICK_INCR "Tick Incr" +#define SS_YAML_KEY_TONE0_PERIOD "Tone0 Period" +#define SS_YAML_KEY_TONE1_PERIOD "Tone1 Period" +#define SS_YAML_KEY_TONE2_PERIOD "Tone2 Period" +#define SS_YAML_KEY_NOISE_PERIOD "Noise Period" +#define SS_YAML_KEY_ENV_PERIOD "Env Period" +#define SS_YAML_KEY_RNG "RNG" +#define SS_YAML_KEY_NOISE_TOGGLE "Noise Toggle" +#define SS_YAML_KEY_ENV_FIRST "Env First" +#define SS_YAML_KEY_ENV_REV "Env Rev" +#define SS_YAML_KEY_ENV_COUNTER "Env Counter" + +#define SS_YAML_KEY_REGISTERS "Registers" +#define SS_YAML_KEY_REG_TONE0_PERIOD "Tone0 Period" +#define SS_YAML_KEY_REG_TONE1_PERIOD "Tone1 Period" +#define SS_YAML_KEY_REG_TONE2_PERIOD "Tone2 Period" +#define SS_YAML_KEY_REG_NOISE_PERIOD "Noise Period" +#define SS_YAML_KEY_REG_MIXER "Mixer" +#define SS_YAML_KEY_REG_VOL0 "Vol0" +#define SS_YAML_KEY_REG_VOL1 "Vol1" +#define SS_YAML_KEY_REG_VOL2 "Vol2" +#define SS_YAML_KEY_REG_ENV_PERIOD "Env Period" +#define SS_YAML_KEY_REG_ENV_SHAPE "Env Shape" +#define SS_YAML_KEY_REG_PORTA "PortA" +#define SS_YAML_KEY_REG_PORTB "PortB" + +#define SS_YAML_KEY_CHANGE "Change" +#define SS_YAML_VALUE_CHANGE_FORMAT "%d, %d, 0x%1X, 0x%02X" + +void CAY8910::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, std::string& suffix) +{ + std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix; + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", unit.c_str()); + + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE0_TICK, ay_tone_tick[0]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE1_TICK, ay_tone_tick[1]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE2_TICK, ay_tone_tick[2]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE0_HIGH, ay_tone_high[0]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE1_HIGH, ay_tone_high[1]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE2_HIGH, ay_tone_high[2]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_NOISE_TICK, ay_noise_tick); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE_SUBCYCLES, ay_tone_subcycles); + yamlSaveHelper.SaveUint(SS_YAML_KEY_ENV_SUBCYCLES, ay_env_subcycles); + yamlSaveHelper.SaveUint(SS_YAML_KEY_ENV_INTERNAL_TICK, ay_env_internal_tick); + yamlSaveHelper.SaveUint(SS_YAML_KEY_ENV_TICK, ay_env_tick); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TICK_INCR, ay_tick_incr); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE0_PERIOD, ay_tone_period[0]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE1_PERIOD, ay_tone_period[1]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE2_PERIOD, ay_tone_period[2]); + yamlSaveHelper.SaveUint(SS_YAML_KEY_NOISE_PERIOD, ay_noise_period); + yamlSaveHelper.SaveUint(SS_YAML_KEY_RNG, rng); + yamlSaveHelper.SaveUint(SS_YAML_KEY_NOISE_TOGGLE, noise_toggle); + yamlSaveHelper.SaveUint(SS_YAML_KEY_ENV_FIRST, env_first); + yamlSaveHelper.SaveUint(SS_YAML_KEY_ENV_REV, env_rev); + yamlSaveHelper.SaveUint(SS_YAML_KEY_ENV_COUNTER, env_counter); + + // New label + { + YamlSaveHelper::Label registers(yamlSaveHelper, "%s:\n", SS_YAML_KEY_REGISTERS); + + yamlSaveHelper.SaveHexUint12(SS_YAML_KEY_REG_TONE0_PERIOD, (UINT)(sound_ay_registers[1]<<8) | sound_ay_registers[0]); + yamlSaveHelper.SaveHexUint12(SS_YAML_KEY_REG_TONE1_PERIOD, (UINT)(sound_ay_registers[3]<<8) | sound_ay_registers[2]); + yamlSaveHelper.SaveHexUint12(SS_YAML_KEY_REG_TONE2_PERIOD, (UINT)(sound_ay_registers[5]<<8) | sound_ay_registers[4]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_NOISE_PERIOD, sound_ay_registers[6]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_MIXER, sound_ay_registers[7]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_VOL0, sound_ay_registers[8]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_VOL1, sound_ay_registers[9]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_VOL2, sound_ay_registers[10]); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REG_ENV_PERIOD, (UINT)(sound_ay_registers[12]<<8) | sound_ay_registers[11]); + yamlSaveHelper.SaveHexUint4(SS_YAML_KEY_REG_ENV_SHAPE, sound_ay_registers[13]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_PORTA, sound_ay_registers[14]); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REG_PORTB, sound_ay_registers[15]); + } + + // New label + if (ay_change_count) + { + YamlSaveHelper::Label change(yamlSaveHelper, "%s:\n", SS_YAML_KEY_CHANGE); + + for (int i=0; i> 8) & 0xf; + period = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_TONE1_PERIOD); + sound_ay_registers[2] = period & 0xff; + sound_ay_registers[3] = (period >> 8) & 0xf; + period = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_TONE2_PERIOD); + sound_ay_registers[4] = period & 0xff; + sound_ay_registers[5] = (period >> 8) & 0xf; + sound_ay_registers[6] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_NOISE_PERIOD); + sound_ay_registers[7] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_MIXER); + sound_ay_registers[8] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_VOL0); + sound_ay_registers[9] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_VOL1); + sound_ay_registers[10] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_VOL2); + period = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_ENV_PERIOD); + sound_ay_registers[11] = period & 0xff; + sound_ay_registers[12] = period >> 8; + sound_ay_registers[13] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_ENV_SHAPE); + sound_ay_registers[14] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_PORTA); + sound_ay_registers[15] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_PORTB); + + yamlLoadHelper.PopMap(); + + ay_change_count = 0; + if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_CHANGE)) + { + while(1) + { + char szIndex[7]; + sprintf_s(szIndex, sizeof(szIndex), "0x%04X", ay_change_count); + + bool bFound; + std::string value = yamlLoadHelper.LoadString_NoThrow(szIndex, bFound); + if (!bFound) + break; // done + + if(4 != sscanf_s(value.c_str(), SS_YAML_VALUE_CHANGE_FORMAT, + &ay_change[ay_change_count].tstates, + &ay_change[ay_change_count].ofs, + &ay_change[ay_change_count].reg, + &ay_change[ay_change_count].val)) + throw std::string("Card: AY8910: Failed to scanf change list"); + + ay_change_count++; + if (ay_change_count > AY_CHANGE_MAX) + throw std::string("Card: AY8910: Too many changes"); + } + + yamlLoadHelper.PopMap(); + } + + yamlLoadHelper.PopMap(); + + return true; +} + /////////////////////////////////////////////////////////////////////////////// // AY8910 interface @@ -996,8 +1190,25 @@ void AY8910_InitClock(int nClock) BYTE* AY8910_GetRegsPtr(UINT uChip) { - if(uChip >= MAX_8910) + if (uChip >= MAX_8910) return NULL; return g_AY8910[uChip].GetAYRegsPtr(); } + +UINT AY8910_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string& suffix) +{ + if (uChip >= MAX_8910) + return 0; + + g_AY8910[uChip].SaveSnapshot(yamlSaveHelper, suffix); + return 1; +} + +UINT AY8910_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT uChip, std::string& suffix) +{ + if (uChip >= MAX_8910) + return 0; + + return g_AY8910[uChip].LoadSnapshot(yamlLoadHelper, suffix) ? 1 : 0; +} diff --git a/source/AY8910.h b/source/AY8910.h index 59a53359..31ad9a15 100644 --- a/source/AY8910.h +++ b/source/AY8910.h @@ -17,6 +17,9 @@ BYTE* AY8910_GetRegsPtr(UINT uChip); void AY8910UpdateSetCycles(); +UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string& suffix); +UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uChip, std::string& suffix); + //------------------------------------- // FUSE stuff @@ -43,8 +46,11 @@ public: void sound_frame( void ); BYTE* GetAYRegsPtr( void ) { return &sound_ay_registers[0]; } static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; } + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, std::string& suffix); + bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, std::string& suffix); private: + void init( void ); void sound_end( void ); void sound_ay_overlay( void ); diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 76a0b3e6..c49a6e0a 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -57,6 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Configuration\PropertySheet.h" #include "Tfe\Tfe.h" +static UINT16 g_AppleWinVersion[4] = {0}; char VERSIONSTRING[16] = "xx.yy.zz.ww"; TCHAR *g_pAppTitle = TITLE_APPLE_2E_ENHANCED; @@ -65,9 +66,6 @@ eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; bool g_bFullSpeed = false; -//Pravets 8A/C variables -bool P8CAPS_ON = false; -bool P8Shift = false; //================================================= // Win32 @@ -102,8 +100,6 @@ CMouseInterface sg_Mouse; SS_CARDTYPE g_Slot4 = CT_Empty; SS_CARDTYPE g_Slot5 = CT_Empty; -eCPU g_ActiveCPU = CPU_6502; - HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed @@ -114,6 +110,22 @@ CSpeech g_Speech; //=========================================================================== +eApple2Type GetApple2Type(void) +{ + return g_Apple2Type; +} + +void SetApple2Type(eApple2Type type) +{ + g_Apple2Type = type; + SetMainCpuDefault(type); +} + +const UINT16* GetAppleWinVersion(void) +{ + return &g_AppleWinVersion[0]; +} + bool GetLoadedSaveStateFlag(void) { return g_bLoadedSaveState; @@ -371,20 +383,39 @@ static void LoadConfigOldJoystick(const UINT uJoyNum) break; } - joytype[uJoyNum] = uNewJoyType; + JoySetJoyType(uJoyNum, uNewJoyType); +} + +//Sets the character set for the Apple model/clone +void SetCharsetType(void) +{ + switch ( GetApple2Type() ) + { + case A2TYPE_APPLE2: g_nCharsetType = 0; break; + case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break; + case A2TYPE_APPLE2E: g_nCharsetType = 0; break; + case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break; + case A2TYPE_PRAVETS82: g_nCharsetType = 1; break; + case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break; + case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. + default: + _ASSERT(0); + g_nCharsetType = 0; + } } //Reads configuration from the registry entries void LoadConfiguration(void) { DWORD dwComputerType; + eApple2Type apple2Type = A2TYPE_APPLE2EENHANCED; if (REGLOAD(TEXT(REGVALUE_APPLE2_TYPE), &dwComputerType)) { if ((dwComputerType >= A2TYPE_MAX) || (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE)) dwComputerType = A2TYPE_APPLE2EENHANCED; - g_Apple2Type = (eApple2Type) dwComputerType; + apple2Type = (eApple2Type) dwComputerType; } else // Support older AppleWin registry entries { @@ -392,27 +423,42 @@ void LoadConfiguration(void) switch (dwComputerType) { // NB. No A2TYPE_APPLE2E (this is correct) - case 0: g_Apple2Type = A2TYPE_APPLE2; - case 1: g_Apple2Type = A2TYPE_APPLE2PLUS; - case 2: g_Apple2Type = A2TYPE_APPLE2EENHANCED; - default: g_Apple2Type = A2TYPE_APPLE2EENHANCED; + case 0: apple2Type = A2TYPE_APPLE2; break; + case 1: apple2Type = A2TYPE_APPLE2PLUS; break; + case 2: apple2Type = A2TYPE_APPLE2EENHANCED; break; + default: apple2Type = A2TYPE_APPLE2EENHANCED; } } - switch (g_Apple2Type) //Sets the character set for the Apple model/clone + SetApple2Type(apple2Type); + SetCharsetType(); + + // + + DWORD dwCpuType; + eCpuType cpu = CPU_65C02; + + if (REGLOAD(TEXT(REGVALUE_CPU_TYPE), &dwCpuType)) { - case A2TYPE_APPLE2: g_nCharsetType = 0; break; - case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break; - case A2TYPE_APPLE2E: g_nCharsetType = 0; break; - case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break; - case A2TYPE_PRAVETS82: g_nCharsetType = 1; break; - case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break; - case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. + if (dwCpuType != CPU_6502 && dwCpuType != CPU_65C02) + dwCpuType = CPU_65C02; + + cpu = (eCpuType) dwCpuType; } - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &joytype[JN_JOYSTICK0])) + SetMainCpu(cpu); + + // + + DWORD dwJoyType; + if (REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &dwJoyType)) + JoySetJoyType(JN_JOYSTICK0, dwJoyType); + else LoadConfigOldJoystick(JN_JOYSTICK0); - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &joytype[JN_JOYSTICK1])) + + if (REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &dwJoyType)) + JoySetJoyType(JN_JOYSTICK1, dwJoyType); + else LoadConfigOldJoystick(JN_JOYSTICK1); REGLOAD(TEXT("Sound Emulation") ,&soundtype); @@ -469,12 +515,6 @@ void LoadConfiguration(void) if(REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) HD_SetEnabled(dwTmp ? true : false); - char szHDVPathname[MAX_PATH] = {0}; - if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_1), 1, szHDVPathname, sizeof(szHDVPathname))) - HD_InsertDisk(HARDDISK_1, szHDVPathname); - if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_2), 1, szHDVPathname, sizeof(szHDVPathname))) - HD_InsertDisk(HARDDISK_2, szHDVPathname); - if(REGLOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp)) JoySetTrim((short)dwTmp, true); if(REGLOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp)) @@ -500,15 +540,20 @@ void LoadConfiguration(void) if(REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp)) g_Slot5 = (SS_CARDTYPE) dwTmp; - if (g_Slot4 == CT_MockingboardC || g_Slot4 == CT_Phasor) - MB_SetSoundcardType(g_Slot4); - else - MB_SetSoundcardType(CT_Empty); - // char szFilename[MAX_PATH] = {0}; + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, szFilename, MAX_PATH); + if (szFilename[0] == 0) + GetCurrentDirectory(sizeof(szFilename), szFilename); + SetCurrentImageDir(szFilename); + + HD_LoadLastDiskImage(HARDDISK_1); + HD_LoadLastDiskImage(HARDDISK_2); + + // + // Current/Starting Dir is the "root" of where the user keeps his disk images RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szFilename, MAX_PATH); if (szFilename[0] == 0) @@ -550,7 +595,7 @@ bool SetCurrentImageDir(const char* pszImageDir) strcpy(g_sCurrentDir, pszImageDir); int nLen = strlen( g_sCurrentDir ); - if( g_sCurrentDir[ nLen - 1 ] != '\\' ) + if ((nLen > 0) && (g_sCurrentDir[ nLen - 1 ] != '\\')) { g_sCurrentDir[ nLen + 0 ] = '\\'; g_sCurrentDir[ nLen + 1 ] = 0; @@ -739,10 +784,12 @@ static int DoDiskInsert(const int nDrive, LPCSTR szFileName) int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { + bool bShutdown = false; bool bSetFullScreen = false; bool bBoot = false; LPSTR szImageName_drive1 = NULL; LPSTR szImageName_drive2 = NULL; + LPSTR szSnapshotName = NULL; const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput while (*lpCmdLine) @@ -774,6 +821,12 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) lpNextArg = GetNextArg(lpNextArg); szImageName_drive2 = lpCmdLine; } + else if (strcmp(lpCmdLine, "-load-state") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + szSnapshotName = lpCmdLine; + } else if (strcmp(lpCmdLine, "-f") == 0) { bSetFullScreen = true; @@ -811,8 +864,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); g_uMaxExPages = atoi(lpCmdLine); - if (g_uMaxExPages > 127) - g_uMaxExPages = 128; + if (g_uMaxExPages > kMaxExMemoryBanks) + g_uMaxExPages = kMaxExMemoryBanks; else if (g_uMaxExPages < 1) g_uMaxExPages = 1; } @@ -905,11 +958,11 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) // Construct version string from fixed file info block - unsigned long major = pFixedFileInfo->dwFileVersionMS >> 16; - unsigned long minor = pFixedFileInfo->dwFileVersionMS & 0xffff; - unsigned long fix = pFixedFileInfo->dwFileVersionLS >> 16; - unsigned long fix_minor = pFixedFileInfo->dwFileVersionLS & 0xffff; - sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow + unsigned long major = g_AppleWinVersion[0] = pFixedFileInfo->dwFileVersionMS >> 16; + unsigned long minor = g_AppleWinVersion[1] = pFixedFileInfo->dwFileVersionMS & 0xffff; + unsigned long fix = g_AppleWinVersion[2] = pFixedFileInfo->dwFileVersionLS >> 16; + unsigned long fix_minor = g_AppleWinVersion[3] = pFixedFileInfo->dwFileVersionLS & 0xffff; + sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow } } @@ -955,7 +1008,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) DiskInitialize(); LogFileOutput("Init: DiskInitialize()\n"); - int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error + int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error if (szImageName_drive1) { nError = DoDiskInsert(DRIVE_1, szImageName_drive1); @@ -1003,7 +1056,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (bShowAboutDlg) { if (!AboutDlg()) - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + bShutdown = true; // Close everything down else RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, VERSIONSTRING); // Only save version after user accepts license } @@ -1019,31 +1072,57 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (!bSysClkOK) { MessageBox(g_hFrameWindow, "DirectX failed to create SystemClock instance", TEXT("AppleWin Error"), MB_OK); - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + bShutdown = true; } if (g_bCustomRomF8Failed) { MessageBox(g_hFrameWindow, "Failed to load custom F8 rom (not found or not exactly 2KB)", TEXT("AppleWin Error"), MB_OK); - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + bShutdown = true; } tfe_init(); LogFileOutput("Main: tfe_init()\n"); - Snapshot_Startup(); // Do this after everything has been init'ed - LogFileOutput("Main: Snapshot_Startup()\n"); - - if (bSetFullScreen) + if (szSnapshotName) { - PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); - bSetFullScreen = false; + // Override value just loaded from Registry by LoadConfiguration() + // . NB. Registry value is not updated with this cmd-line value + Snapshot_SetFilename(szSnapshotName); + Snapshot_LoadState(); + bBoot = true; +#if _DEBUG && 0 // Debug/test: Save a duplicate of the save-state file in tmp folder + std::string saveName = std::string("tmp\\") + std::string(szSnapshotName); + Snapshot_SetFilename(saveName); + g_bSaveStateOnExit = true; + bShutdown = true; +#endif + szSnapshotName = NULL; + } + else + { + Snapshot_Startup(); // Do this after everything has been init'ed + LogFileOutput("Main: Snapshot_Startup()\n"); } - if (bBoot) + if (bShutdown) { - PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); - bBoot = false; + PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + // NB. If shutting down, then don't post any other messages (GH#286) + } + else + { + if (bSetFullScreen) + { + PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); + bSetFullScreen = false; + } + + if (bBoot) + { + PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); + bBoot = false; + } } // ENTER THE MAIN MESSAGE LOOP diff --git a/source/Applewin.h b/source/Applewin.h index 24f19fd2..b57efcde 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -1,23 +1,23 @@ #pragma once -#include "Structs.h" +#include "SaveState_Structs_common.h" #include "Common.h" void SetCurrentCLK6502(); bool SetCurrentImageDir(const char* pszImageDir); +void SetCharsetType(void); - +extern const UINT16* GetAppleWinVersion(void); extern char VERSIONSTRING[]; // Constructed in WinMain() extern TCHAR *g_pAppTitle; extern eApple2Type g_Apple2Type; +eApple2Type GetApple2Type(void); +void SetApple2Type(eApple2Type type); extern bool g_bFullSpeed; -//Pravets 8A/C only variables -extern bool P8CAPS_ON; -extern bool P8Shift; //=========================================== // Win32 @@ -49,9 +49,6 @@ extern SS_CARDTYPE g_Slot5; // Mockingboard, Z80, in slot5 extern HANDLE g_hCustomRomF8; // NULL if no custom rom -enum eCPU {CPU_6502=1, CPU_Z80}; -extern eCPU g_ActiveCPU; - #ifdef USE_SPEECH_API class CSpeech; extern CSpeech g_Speech; diff --git a/source/CPU.cpp b/source/CPU.cpp index faf45fbf..daacf9fc 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -63,7 +63,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // What about these: // . 65C02: STZ?, TRB?, TSB? -// . Answer: TRB & TSB don't have affected adressing modes +// . Answer: TRB & TSB don't have affected addressing modes // . STZ probably doesn't add a cycle since otherwise it would be slower than STA which doesn't make sense. // // NB. 'Zero-page indexed' opcodes wrap back to zero-page. @@ -103,6 +103,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Z80VICE\z80mem.h" #include "Debugger\Debug.h" +#include "YamlHelper.h" // 6502 Accumulator Bit Flags #define AF_SIGN 0x80 @@ -148,6 +149,53 @@ static volatile UINT32 g_bmIRQ = 0; static volatile UINT32 g_bmNMI = 0; static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line +// + +static eCpuType g_MainCPU = CPU_65C02; +static eCpuType g_ActiveCPU = CPU_65C02; + +eCpuType GetMainCpu(void) +{ + return g_MainCPU; +} + +void SetMainCpu(eCpuType cpu) +{ + _ASSERT(cpu != CPU_Z80); + if (cpu == CPU_Z80) + return; + + g_MainCPU = cpu; +} + +static bool IsCpu65C02(eApple2Type apple2Type) +{ + // NB. All Pravets clones are 6502 (GH#307) + return (apple2Type == A2TYPE_APPLE2EENHANCED) || (apple2Type & A2TYPE_APPLE2C); +} + +eCpuType ProbeMainCpuDefault(eApple2Type apple2Type) +{ + return IsCpu65C02(apple2Type) ? CPU_65C02 : CPU_6502; +} + +void SetMainCpuDefault(eApple2Type apple2Type) +{ + SetMainCpu( ProbeMainCpuDefault(apple2Type) ); +} + +eCpuType GetActiveCpu(void) +{ + return g_ActiveCPU; +} + +void SetActiveCpu(eCpuType cpu) +{ + g_ActiveCPU = cpu; +} + +// + #include "cpu/cpu_general.inl" #include "cpu/cpu_instructions.inl" @@ -409,8 +457,8 @@ static __forceinline void CheckInterruptSources(ULONG uExecutedCycles) static DWORD InternalCpuExecute (DWORD uTotalCycles) { - if (IS_APPLE2 || (g_Apple2Type == A2TYPE_APPLE2E)) - return Cpu6502(uTotalCycles); // Apple ][, ][+, //e + if (GetMainCpu() == CPU_6502) + return Cpu6502(uTotalCycles); // Apple ][, ][+, //e, Clones else return Cpu65C02(uTotalCycles); // Enhanced Apple //e } @@ -639,36 +687,83 @@ void CpuReset() regs.bJammed = 0; - g_ActiveCPU = CPU_6502; + SetActiveCpu( GetMainCpu() ); z80_reset(); } //=========================================================================== -DWORD CpuGetSnapshot(SS_CPU6502* pSS) +void CpuSetSnapshot_v1(const BYTE A, const BYTE X, const BYTE Y, const BYTE P, const BYTE SP, const USHORT PC, const unsigned __int64 CumulativeCycles) { - pSS->A = regs.a; - pSS->X = regs.x; - pSS->Y = regs.y; - pSS->P = regs.ps | AF_RESERVED | AF_BREAK; - pSS->S = (BYTE) (regs.sp & 0xff); - pSS->PC = regs.pc; - pSS->g_nCumulativeCycles = g_nCumulativeCycles; + regs.a = A; + regs.x = X; + regs.y = Y; + regs.ps = P | (AF_RESERVED | AF_BREAK); + regs.sp = ((USHORT)SP) | 0x100; + regs.pc = PC; - return 0; -} - -DWORD CpuSetSnapshot(SS_CPU6502* pSS) -{ - regs.a = pSS->A; - regs.x = pSS->X; - regs.y = pSS->Y; - regs.ps = pSS->P | AF_RESERVED | AF_BREAK; - regs.sp = (USHORT)pSS->S | 0x100; - regs.pc = pSS->PC; CpuIrqReset(); CpuNmiReset(); - g_nCumulativeCycles = pSS->g_nCumulativeCycles; - - return 0; + g_nCumulativeCycles = CumulativeCycles; +} + +// + +#define SS_YAML_KEY_CPU_TYPE "Type" +#define SS_YAML_KEY_REGA "A" +#define SS_YAML_KEY_REGX "X" +#define SS_YAML_KEY_REGY "Y" +#define SS_YAML_KEY_REGP "P" +#define SS_YAML_KEY_REGS "S" +#define SS_YAML_KEY_REGPC "PC" +#define SS_YAML_KEY_CUMULATIVECYCLES "Cumulative Cycles" + +#define SS_YAML_VALUE_6502 "6502" +#define SS_YAML_VALUE_65C02 "65C02" + +static std::string CpuGetSnapshotStructName(void) +{ + static const std::string name("CPU"); + return name; +} + +void CpuSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + regs.ps |= (AF_RESERVED | AF_BREAK); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", CpuGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveString(SS_YAML_KEY_CPU_TYPE, GetMainCpu() == CPU_6502 ? SS_YAML_VALUE_6502 : SS_YAML_VALUE_65C02); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGA, regs.a); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGX, regs.x); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGY, regs.y); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGP, regs.ps); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGS, (BYTE) regs.sp); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGPC, regs.pc); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CUMULATIVECYCLES, g_nCumulativeCycles); +} + +void CpuLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(CpuGetSnapshotStructName())) + return; + + std::string cpuType = yamlLoadHelper.LoadString(SS_YAML_KEY_CPU_TYPE); + eCpuType cpu; + if (cpuType == SS_YAML_VALUE_6502) cpu = CPU_6502; + else if (cpuType == SS_YAML_VALUE_65C02) cpu = CPU_65C02; + else throw std::string("Load: Unknown main CPU type"); + SetMainCpu(cpu); + + regs.a = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGA); + regs.x = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGX); + regs.y = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGY); + regs.ps = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGP) | (AF_RESERVED | AF_BREAK); + regs.sp = (USHORT) ((yamlLoadHelper.LoadUint(SS_YAML_KEY_REGS) & 0xff) | 0x100); + regs.pc = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGPC); + + CpuIrqReset(); + CpuNmiReset(); + g_nCumulativeCycles = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CUMULATIVECYCLES); + + yamlLoadHelper.PopMap(); } diff --git a/source/CPU.h b/source/CPU.h index 58c5d886..5086e9e1 100644 --- a/source/CPU.h +++ b/source/CPU.h @@ -1,6 +1,7 @@ #pragma once -typedef struct _regsrec { +struct regsrec +{ BYTE a; // accumulator BYTE x; // index X BYTE y; // index Y @@ -8,7 +9,7 @@ typedef struct _regsrec { WORD pc; // program counter WORD sp; // stack pointer BYTE bJammed; // CPU has crashed (NMOS 6502 only) -} regsrec, *regsptr; +}; extern regsrec regs; extern unsigned __int64 g_nCumulativeCycles; @@ -26,10 +27,20 @@ void CpuNmiReset(); void CpuNmiAssert(eIRQSRC Device); void CpuNmiDeassert(eIRQSRC Device); void CpuReset (); -DWORD CpuGetSnapshot(SS_CPU6502* pSS); -DWORD CpuSetSnapshot(SS_CPU6502* pSS); +void CpuSetSnapshot_v1(const BYTE A, const BYTE X, const BYTE Y, const BYTE P, const BYTE SP, const USHORT PC, const unsigned __int64 CumulativeCycles); +void CpuSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void CpuLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE CpuRead(USHORT addr, ULONG uExecutedCycles); void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles); DWORD CpuGetEmulationTime_ms(void); + +enum eCpuType {CPU_6502=1, CPU_65C02, CPU_Z80}; // Don't change! Persisted to Registry + +eCpuType GetMainCpu(void); +void SetMainCpu(eCpuType cpu); +eCpuType ProbeMainCpuDefault(eApple2Type apple2Type); +void SetMainCpuDefault(eApple2Type apple2Type); +eCpuType GetActiveCpu(void); +void SetActiveCpu(eCpuType cpu); diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index 3645242e..b2a25e67 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -35,7 +35,6 @@ static DWORD Cpu6502 (DWORD uTotalCycles) WORD val; AF_TO_EF ULONG uExecutedCycles = 0; - BOOL bSlowerOnPagecross = 0; // Set if opcode writes to memory (eg. ASL, STA) WORD base; g_bDebugBreakpointHit = 0; @@ -49,275 +48,276 @@ static DWORD Cpu6502 (DWORD uTotalCycles) ULONG uPreviousCycles = uExecutedCycles; // NTSC_END - if (g_ActiveCPU == CPU_Z80) + if (GetActiveCpu() == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) } else { - if (!Fetch(iOpcode, uExecutedCycles)) - break; + if (!Fetch(iOpcode, uExecutedCycles)) + break; #define $ INV // INV = Invalid -> Debugger Break - switch (iOpcode) - { - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: $ HLT CYC(2) break; - case 0x03: $ idx ASO CYC(8) break; - case 0x04: $ ZPG NOP CYC(3) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASLn CYC(5) break; - case 0x07: $ ZPG ASO CYC(5) break; // invalid - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: $ IMM ANC CYC(2) break; // invald - case 0x0C: $ abx NOP CYC(4) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASLn CYC(6) break; - case 0x0F: $ ABS ASO CYC(6) break; // invalid - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: $ HLT CYC(2) break; - case 0x13: $ idy ASO CYC(8) break; // invalid - case 0x14: $ zpx NOP CYC(4) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASLn CYC(6) break; - case 0x17: $ zpx ASO CYC(6) break; // invalid - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: $ NOP CYC(2) break; - case 0x1B: $ aby ASO CYC(7) break; // invalid - case 0x1C: $ abx NOP CYC(4) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASLn CYC(6) break; - case 0x1F: $ abx ASO CYC(7) break; // invalid - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: $ HLT CYC(2) break; - case 0x23: $ idx RLA CYC(8) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROLn CYC(5) break; - case 0x27: $ ZPG RLA CYC(5) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: $ IMM ANC CYC(2) break; // invalid - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROLn CYC(6) break; - case 0x2F: $ ABS RLA CYC(6) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: $ HLT CYC(2) break; - case 0x33: $ idy RLA CYC(8) break; // invalid - case 0x34: $ zpx NOP CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROLn CYC(6) break; - case 0x37: $ zpx RLA CYC(6) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: $ NOP CYC(2) break; - case 0x3B: $ aby RLA CYC(7) break; // invalid - case 0x3C: $ abx NOP CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROLn CYC(6) break; - case 0x3F: $ abx RLA CYC(7) break; // invalid - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: $ HLT CYC(2) break; - case 0x43: $ idx LSE CYC(8) break; // invalid - case 0x44: $ ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSRn CYC(5) break; - case 0x47: $ ZPG LSE CYC(5) break; // invalid - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: $ IMM ALR CYC(2) break; // invalid - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSRn CYC(6) break; - case 0x4F: $ ABS LSE CYC(6) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: $ HLT CYC(2) break; - case 0x53: $ idy LSE CYC(8) break; - case 0x54: $ zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSRn CYC(6) break; - case 0x57: $ zpx LSE CYC(6) break; // invalid - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: $ NOP CYC(2) break; - case 0x5B: $ aby LSE CYC(7) break; // invalid - case 0x5C: $ abx NOP CYC(4) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSRn CYC(6) break; - case 0x5F: $ abx LSE CYC(7) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADCn CYC(6) break; - case 0x62: $ HLT CYC(2) break; - case 0x63: $ idx RRA CYC(8) break; // invalid - case 0x64: $ ZPG NOP CYC(3) break; - case 0x65: ZPG ADCn CYC(3) break; - case 0x66: ZPG RORn CYC(5) break; - case 0x67: $ ZPG RRA CYC(5) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADCn CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: $ IMM ARR CYC(2) break; // invalid - case 0x6C: IABSNMOS JMP CYC(6) break; - case 0x6D: ABS ADCn CYC(4) break; - case 0x6E: ABS RORn CYC(6) break; - case 0x6F: $ ABS RRA CYC(6) break; // invalid - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADCn CYC(5) break; - case 0x72: $ HLT CYC(2) break; - case 0x73: $ idy RRA CYC(8) break; // invalid - case 0x74: $ zpx NOP CYC(4) break; - case 0x75: zpx ADCn CYC(4) break; - case 0x76: zpx RORn CYC(6) break; - case 0x77: $ zpx RRA CYC(6) break; // invalid - case 0x78: SEI CYC(2) break; - case 0x79: aby ADCn CYC(4) break; - case 0x7A: $ NOP CYC(2) break; - case 0x7B: $ aby RRA CYC(7) break; // invalid - case 0x7C: $ abx NOP CYC(4) break; - case 0x7D: abx ADCn CYC(4) break; - case 0x7E: abx RORn CYC(6) break; - case 0x7F: $ abx RRA CYC(7) break; // invalid - case 0x80: $ IMM NOP CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: $ IMM NOP CYC(2) break; - case 0x83: $ idx AXS CYC(6) break; // invalid - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: $ ZPG AXS CYC(3) break; // invalid - case 0x88: DEY CYC(2) break; - case 0x89: $ IMM NOP CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: $ IMM XAA CYC(2) break; // invalid - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: $ ABS AXS CYC(4) break; // invalid - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: $ HLT CYC(2) break; - case 0x93: $ idy AXA CYC(6) break; // invalid - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: $ zpy AXS CYC(4) break; // invalid - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: $ aby TAS CYC(5) break; // invalid - case 0x9C: $ abx SAY CYC(5) break; // invalid - case 0x9D: abx STA CYC(5) break; - case 0x9E: $ aby XAS CYC(5) break; - case 0x9F: $ aby AXA CYC(5) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: $ idx LAX CYC(6) break; // invalid - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: $ ZPG LAX CYC(3) break; // invalid - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: $ IMM OAL CYC(2) break; // invalid - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: $ ABS LAX CYC(4) break; // invalid - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: $ HLT CYC(2) break; - case 0xB3: $ idy LAX CYC(5) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: $ zpy LAX CYC(4) break; // invalid - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: $ aby LAS CYC(4) break; // invalid - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: $ aby LAX CYC(4) break; // invalid - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: $ IMM NOP CYC(2) break; - case 0xC3: $ idx DCM CYC(8) break; // invalid - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DECn CYC(5) break; - case 0xC7: $ ZPG DCM CYC(5) break; // invalid - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: $ IMM SAX CYC(2) break; // invalid - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DECn CYC(5) break; - case 0xCF: $ ABS DCM CYC(6) break; // invalid - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: $ HLT CYC(2) break; - case 0xD3: $ idy DCM CYC(8) break; // invalid - case 0xD4: $ zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DECn CYC(6) break; - case 0xD7: $ zpx DCM CYC(6) break; // invalid - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: $ NOP CYC(2) break; - case 0xDB: $ aby DCM CYC(7) break; // invalid - case 0xDC: $ abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DECn CYC(6) break; - case 0xDF: $ abx DCM CYC(7) break; // invalid - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBCn CYC(6) break; - case 0xE2: $ IMM NOP CYC(2) break; - case 0xE3: $ idx INS CYC(8) break; // invalid - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBCn CYC(3) break; - case 0xE6: ZPG INCn CYC(5) break; - case 0xE7: $ ZPG INS CYC(5) break; // invalid - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBCn CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: $ IMM SBCn CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBCn CYC(4) break; - case 0xEE: ABS INCn CYC(6) break; - case 0xEF: $ ABS INS CYC(6) break; // invalid - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBCn CYC(5) break; - case 0xF2: $ HLT CYC(2) break; - case 0xF3: $ idy INS CYC(8) break; // invalid - case 0xF4: $ zpx NOP CYC(4) break; - case 0xF5: zpx SBCn CYC(4) break; - case 0xF6: zpx INCn CYC(6) break; - case 0xF7: $ zpx INS CYC(6) break; // invalid - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBCn CYC(4) break; - case 0xFA: $ NOP CYC(2) break; - case 0xFB: $ aby INS CYC(7) break; - case 0xFC: $ abx NOP CYC(4) break; - case 0xFD: abx SBCn CYC(4) break; - case 0xFE: abx INCn CYC(6) break; - case 0xFF: $ abx INS CYC(7) break; - } + switch (iOpcode) + { + case 0x00: BRK CYC(7) break; + case 0x01: idx ORA CYC(6) break; + case 0x02: $ HLT CYC(2) break; + case 0x03: $ idx ASO CYC(8) break; + case 0x04: $ ZPG NOP CYC(3) break; + case 0x05: ZPG ORA CYC(3) break; + case 0x06: ZPG ASLn CYC(5) break; + case 0x07: $ ZPG ASO CYC(5) break; + case 0x08: PHP CYC(3) break; + case 0x09: IMM ORA CYC(2) break; + case 0x0A: asl CYC(2) break; + case 0x0B: $ IMM ANC CYC(2) break; + case 0x0C: $ ABSX_OPT NOP CYC(4) break; + case 0x0D: ABS ORA CYC(4) break; + case 0x0E: ABS ASLn CYC(6) break; + case 0x0F: $ ABS ASO CYC(6) break; + case 0x10: REL BPL CYC(2) break; + case 0x11: INDY_OPT ORA CYC(5) break; + case 0x12: $ HLT CYC(2) break; + case 0x13: $ INDY_CONST ASO CYC(8) break; + case 0x14: $ zpx NOP CYC(4) break; + case 0x15: zpx ORA CYC(4) break; + case 0x16: zpx ASLn CYC(6) break; + case 0x17: $ zpx ASO CYC(6) break; + case 0x18: CLC CYC(2) break; + case 0x19: ABSY_OPT ORA CYC(4) break; + case 0x1A: $ NOP CYC(2) break; + case 0x1B: $ ABSY_CONST ASO CYC(7) break; + case 0x1C: $ ABSX_OPT NOP CYC(4) break; + case 0x1D: ABSX_OPT ORA CYC(4) break; + case 0x1E: ABSX_CONST ASLn CYC(7) break; + case 0x1F: $ ABSX_CONST ASO CYC(7) break; + case 0x20: ABS JSR CYC(6) break; + case 0x21: idx AND CYC(6) break; + case 0x22: $ HLT CYC(2) break; + case 0x23: $ idx RLA CYC(8) break; + case 0x24: ZPG BIT CYC(3) break; + case 0x25: ZPG AND CYC(3) break; + case 0x26: ZPG ROLn CYC(5) break; + case 0x27: $ ZPG RLA CYC(5) break; + case 0x28: PLP CYC(4) break; + case 0x29: IMM AND CYC(2) break; + case 0x2A: rol CYC(2) break; + case 0x2B: $ IMM ANC CYC(2) break; + case 0x2C: ABS BIT CYC(4) break; + case 0x2D: ABS AND CYC(4) break; + case 0x2E: ABS ROLn CYC(6) break; + case 0x2F: $ ABS RLA CYC(6) break; + case 0x30: REL BMI CYC(2) break; + case 0x31: INDY_OPT AND CYC(5) break; + case 0x32: $ HLT CYC(2) break; + case 0x33: $ INDY_CONST RLA CYC(8) break; + case 0x34: $ zpx NOP CYC(4) break; + case 0x35: zpx AND CYC(4) break; + case 0x36: zpx ROLn CYC(6) break; + case 0x37: $ zpx RLA CYC(6) break; + case 0x38: SEC CYC(2) break; + case 0x39: ABSY_OPT AND CYC(4) break; + case 0x3A: $ NOP CYC(2) break; + case 0x3B: $ ABSY_CONST RLA CYC(7) break; + case 0x3C: $ ABSX_OPT NOP CYC(4) break; + case 0x3D: ABSX_OPT AND CYC(4) break; + case 0x3E: ABSX_CONST ROLn CYC(6) break; + case 0x3F: $ ABSX_CONST RLA CYC(7) break; + case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; + case 0x41: idx EOR CYC(6) break; + case 0x42: $ HLT CYC(2) break; + case 0x43: $ idx LSE CYC(8) break; + case 0x44: $ ZPG NOP CYC(3) break; + case 0x45: ZPG EOR CYC(3) break; + case 0x46: ZPG LSRn CYC(5) break; + case 0x47: $ ZPG LSE CYC(5) break; + case 0x48: PHA CYC(3) break; + case 0x49: IMM EOR CYC(2) break; + case 0x4A: lsr CYC(2) break; + case 0x4B: $ IMM ALR CYC(2) break; + case 0x4C: ABS JMP CYC(3) break; + case 0x4D: ABS EOR CYC(4) break; + case 0x4E: ABS LSRn CYC(6) break; + case 0x4F: $ ABS LSE CYC(6) break; + case 0x50: REL BVC CYC(2) break; + case 0x51: INDY_OPT EOR CYC(5) break; + case 0x52: $ HLT CYC(2) break; + case 0x53: $ INDY_CONST LSE CYC(8) break; + case 0x54: $ zpx NOP CYC(4) break; + case 0x55: zpx EOR CYC(4) break; + case 0x56: zpx LSRn CYC(6) break; + case 0x57: $ zpx LSE CYC(6) break; + case 0x58: CLI CYC(2) break; + case 0x59: ABSY_OPT EOR CYC(4) break; + case 0x5A: $ NOP CYC(2) break; + case 0x5B: $ ABSY_CONST LSE CYC(7) break; + case 0x5C: $ ABSX_OPT NOP CYC(4) break; + case 0x5D: ABSX_OPT EOR CYC(4) break; + case 0x5E: ABSX_CONST LSRn CYC(6) break; + case 0x5F: $ ABSX_CONST LSE CYC(7) break; + case 0x60: RTS CYC(6) break; + case 0x61: idx ADCn CYC(6) break; + case 0x62: $ HLT CYC(2) break; + case 0x63: $ idx RRA CYC(8) break; + case 0x64: $ ZPG NOP CYC(3) break; + case 0x65: ZPG ADCn CYC(3) break; + case 0x66: ZPG RORn CYC(5) break; + case 0x67: $ ZPG RRA CYC(5) break; + case 0x68: PLA CYC(4) break; + case 0x69: IMM ADCn CYC(2) break; + case 0x6A: ror CYC(2) break; + case 0x6B: $ IMM ARR CYC(2) break; + case 0x6C: IABS_NMOS JMP CYC(5) break; // GH#264 + case 0x6D: ABS ADCn CYC(4) break; + case 0x6E: ABS RORn CYC(6) break; + case 0x6F: $ ABS RRA CYC(6) break; + case 0x70: REL BVS CYC(2) break; + case 0x71: INDY_OPT ADCn CYC(5) break; + case 0x72: $ HLT CYC(2) break; + case 0x73: $ INDY_CONST RRA CYC(8) break; + case 0x74: $ zpx NOP CYC(4) break; + case 0x75: zpx ADCn CYC(4) break; + case 0x76: zpx RORn CYC(6) break; + case 0x77: $ zpx RRA CYC(6) break; + case 0x78: SEI CYC(2) break; + case 0x79: ABSY_OPT ADCn CYC(4) break; + case 0x7A: $ NOP CYC(2) break; + case 0x7B: $ ABSY_CONST RRA CYC(7) break; + case 0x7C: $ ABSX_OPT NOP CYC(4) break; + case 0x7D: ABSX_OPT ADCn CYC(4) break; + case 0x7E: ABSX_CONST RORn CYC(6) break; + case 0x7F: $ ABSX_CONST RRA CYC(7) break; + case 0x80: $ IMM NOP CYC(2) break; + case 0x81: idx STA CYC(6) break; + case 0x82: $ IMM NOP CYC(2) break; + case 0x83: $ idx AXS CYC(6) break; + case 0x84: ZPG STY CYC(3) break; + case 0x85: ZPG STA CYC(3) break; + case 0x86: ZPG STX CYC(3) break; + case 0x87: $ ZPG AXS CYC(3) break; + case 0x88: DEY CYC(2) break; + case 0x89: $ IMM NOP CYC(2) break; + case 0x8A: TXA CYC(2) break; + case 0x8B: $ IMM XAA CYC(2) break; + case 0x8C: ABS STY CYC(4) break; + case 0x8D: ABS STA CYC(4) break; + case 0x8E: ABS STX CYC(4) break; + case 0x8F: $ ABS AXS CYC(4) break; + case 0x90: REL BCC CYC(2) break; + case 0x91: INDY_CONST STA CYC(6) break; + case 0x92: $ HLT CYC(2) break; + case 0x93: $ INDY_CONST AXA CYC(6) break; + case 0x94: zpx STY CYC(4) break; + case 0x95: zpx STA CYC(4) break; + case 0x96: zpy STX CYC(4) break; + case 0x97: $ zpy AXS CYC(4) break; + case 0x98: TYA CYC(2) break; + case 0x99: ABSY_CONST STA CYC(5) break; + case 0x9A: TXS CYC(2) break; + case 0x9B: $ ABSY_CONST TAS CYC(5) break; + case 0x9C: $ ABSX_CONST SAY CYC(5) break; + case 0x9D: ABSX_CONST STA CYC(5) break; + case 0x9E: $ ABSY_CONST XAS CYC(5) break; + case 0x9F: $ ABSY_CONST AXA CYC(5) break; + case 0xA0: IMM LDY CYC(2) break; + case 0xA1: idx LDA CYC(6) break; + case 0xA2: IMM LDX CYC(2) break; + case 0xA3: $ idx LAX CYC(6) break; + case 0xA4: ZPG LDY CYC(3) break; + case 0xA5: ZPG LDA CYC(3) break; + case 0xA6: ZPG LDX CYC(3) break; + case 0xA7: $ ZPG LAX CYC(3) break; + case 0xA8: TAY CYC(2) break; + case 0xA9: IMM LDA CYC(2) break; + case 0xAA: TAX CYC(2) break; + case 0xAB: $ IMM OAL CYC(2) break; + case 0xAC: ABS LDY CYC(4) break; + case 0xAD: ABS LDA CYC(4) break; + case 0xAE: ABS LDX CYC(4) break; + case 0xAF: $ ABS LAX CYC(4) break; + case 0xB0: REL BCS CYC(2) break; + case 0xB1: INDY_OPT LDA CYC(5) break; + case 0xB2: $ HLT CYC(2) break; + case 0xB3: $ INDY_OPT LAX CYC(5) break; + case 0xB4: zpx LDY CYC(4) break; + case 0xB5: zpx LDA CYC(4) break; + case 0xB6: zpy LDX CYC(4) break; + case 0xB7: $ zpy LAX CYC(4) break; + case 0xB8: CLV CYC(2) break; + case 0xB9: ABSY_OPT LDA CYC(4) break; + case 0xBA: TSX CYC(2) break; + case 0xBB: $ ABSY_OPT LAS CYC(4) break; + case 0xBC: ABSX_OPT LDY CYC(4) break; + case 0xBD: ABSX_OPT LDA CYC(4) break; + case 0xBE: ABSY_OPT LDX CYC(4) break; + case 0xBF: $ ABSY_OPT LAX CYC(4) break; + case 0xC0: IMM CPY CYC(2) break; + case 0xC1: idx CMP CYC(6) break; + case 0xC2: $ IMM NOP CYC(2) break; + case 0xC3: $ idx DCM CYC(8) break; + case 0xC4: ZPG CPY CYC(3) break; + case 0xC5: ZPG CMP CYC(3) break; + case 0xC6: ZPG DEC CYC(5) break; + case 0xC7: $ ZPG DCM CYC(5) break; + case 0xC8: INY CYC(2) break; + case 0xC9: IMM CMP CYC(2) break; + case 0xCA: DEX CYC(2) break; + case 0xCB: $ IMM SAX CYC(2) break; + case 0xCC: ABS CPY CYC(4) break; + case 0xCD: ABS CMP CYC(4) break; + case 0xCE: ABS DEC CYC(6) break; + case 0xCF: $ ABS DCM CYC(6) break; + case 0xD0: REL BNE CYC(2) break; + case 0xD1: INDY_OPT CMP CYC(5) break; + case 0xD2: $ HLT CYC(2) break; + case 0xD3: $ INDY_CONST DCM CYC(8) break; + case 0xD4: $ zpx NOP CYC(4) break; + case 0xD5: zpx CMP CYC(4) break; + case 0xD6: zpx DEC CYC(6) break; + case 0xD7: $ zpx DCM CYC(6) break; + case 0xD8: CLD CYC(2) break; + case 0xD9: ABSY_OPT CMP CYC(4) break; + case 0xDA: $ NOP CYC(2) break; + case 0xDB: $ ABSY_CONST DCM CYC(7) break; + case 0xDC: $ ABSX_OPT NOP CYC(4) break; + case 0xDD: ABSX_OPT CMP CYC(4) break; + case 0xDE: ABSX_CONST DEC CYC(7) break; + case 0xDF: $ ABSX_CONST DCM CYC(7) break; + case 0xE0: IMM CPX CYC(2) break; + case 0xE1: idx SBCn CYC(6) break; + case 0xE2: $ IMM NOP CYC(2) break; + case 0xE3: $ idx INS CYC(8) break; + case 0xE4: ZPG CPX CYC(3) break; + case 0xE5: ZPG SBCn CYC(3) break; + case 0xE6: ZPG INC CYC(5) break; + case 0xE7: $ ZPG INS CYC(5) break; + case 0xE8: INX CYC(2) break; + case 0xE9: IMM SBCn CYC(2) break; + case 0xEA: NOP CYC(2) break; + case 0xEB: $ IMM SBCn CYC(2) break; + case 0xEC: ABS CPX CYC(4) break; + case 0xED: ABS SBCn CYC(4) break; + case 0xEE: ABS INC CYC(6) break; + case 0xEF: $ ABS INS CYC(6) break; + case 0xF0: REL BEQ CYC(2) break; + case 0xF1: INDY_OPT SBCn CYC(5) break; + case 0xF2: $ HLT CYC(2) break; + case 0xF3: $ INDY_CONST INS CYC(8) break; + case 0xF4: $ zpx NOP CYC(4) break; + case 0xF5: zpx SBCn CYC(4) break; + case 0xF6: zpx INC CYC(6) break; + case 0xF7: $ zpx INS CYC(6) break; + case 0xF8: SED CYC(2) break; + case 0xF9: ABSY_OPT SBCn CYC(4) break; + case 0xFA: $ NOP CYC(2) break; + case 0xFB: $ ABSY_CONST INS CYC(7) break; + case 0xFC: $ ABSX_OPT NOP CYC(4) break; + case 0xFD: ABSX_OPT SBCn CYC(4) break; + case 0xFE: ABSX_CONST INC CYC(7) break; + case 0xFF: $ ABSX_CONST INS CYC(7) break; + } +#undef $ } // NTSC_BEGIN diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index a85e3c04..d9ad28c5 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -38,7 +38,6 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) WORD val; AF_TO_EF ULONG uExecutedCycles = 0; - BOOL bSlowerOnPagecross = 0; // Set if opcode writes to memory (eg. ASL, STA) WORD base; g_bDebugBreakpointHit = 0; @@ -52,7 +51,7 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) ULONG uPreviousCycles = uExecutedCycles; // NTSC_END - if (g_ActiveCPU == CPU_Z80) + if (GetActiveCpu() == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) } @@ -61,265 +60,265 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) if (!Fetch(iOpcode, uExecutedCycles)) break; +#define $ INV // INV = Invalid -> Debugger Break switch (iOpcode) { -#define $ INV // INV = Invalid -> Debugger Break - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: $ IMM NOP CYC(2) break; - case 0x03: $ NOP CYC(2) break; - case 0x04: ZPG TSB CYC(5) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASLc CYC(5) break; - case 0x07: $ NOP CYC(2) break; - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: $ NOP CYC(2) break; - case 0x0C: ABS TSB CYC(6) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASLc CYC(6) break; - case 0x0F: $ NOP CYC(2) break; - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: izp ORA CYC(5) break; - case 0x13: $ NOP CYC(2) break; - case 0x14: ZPG TRB CYC(5) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASLc CYC(6) break; - case 0x17: $ NOP CYC(2) break; - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: INA CYC(2) break; - case 0x1B: $ NOP CYC(2) break; - case 0x1C: ABS TRB CYC(6) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASLc CYC(6) break; - case 0x1F: $ NOP CYC(2) break; - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: $ IMM NOP CYC(2) break; - case 0x23: $ NOP CYC(2) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROLc CYC(5) break; - case 0x27: $ NOP CYC(2) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: $ NOP CYC(2) break; - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROLc CYC(6) break; - case 0x2F: $ NOP CYC(2) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: izp AND CYC(5) break; - case 0x33: $ NOP CYC(2) break; - case 0x34: zpx BIT CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROLc CYC(6) break; - case 0x37: $ NOP CYC(2) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: DEA CYC(2) break; - case 0x3B: $ NOP CYC(2) break; - case 0x3C: abx BIT CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROLc CYC(6) break; - case 0x3F: $ NOP CYC(2) break; - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: $ IMM NOP CYC(2) break; - case 0x43: $ NOP CYC(2) break; - case 0x44: $ ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSRc CYC(5) break; - case 0x47: $ NOP CYC(2) break; - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: $ NOP CYC(2) break; - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSRc CYC(6) break; - case 0x4F: $ NOP CYC(2) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: izp EOR CYC(5) break; - case 0x53: $ NOP CYC(2) break; - case 0x54: $ zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSRc CYC(6) break; - case 0x57: $ NOP CYC(2) break; - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: PHY CYC(3) break; - case 0x5B: $ NOP CYC(2) break; - case 0x5C: $ abx NOP CYC(8) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSRc CYC(6) break; - case 0x5F: $ NOP CYC(2) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADCc CYC(6) break; - case 0x62: $ IMM NOP CYC(2) break; - case 0x63: $ NOP CYC(2) break; - case 0x64: ZPG STZ CYC(3) break; - case 0x65: ZPG ADCc CYC(3) break; - case 0x66: ZPG RORc CYC(5) break; - case 0x67: $ NOP CYC(2) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADCc CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: $ NOP CYC(2) break; - case 0x6C: IABSCMOS JMP CYC(6) break; - case 0x6D: ABS ADCc CYC(4) break; - case 0x6E: ABS RORc CYC(6) break; - case 0x6F: $ NOP CYC(2) break; - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADCc CYC(5) break; - case 0x72: izp ADCc CYC(5) break; - case 0x73: $ NOP CYC(2) break; - case 0x74: zpx STZ CYC(4) break; - case 0x75: zpx ADCc CYC(4) break; - case 0x76: zpx RORc CYC(6) break; - case 0x77: $ NOP CYC(2) break; - case 0x78: SEI CYC(2) break; - case 0x79: aby ADCc CYC(4) break; - case 0x7A: PLY CYC(4) break; - case 0x7B: $ NOP CYC(2) break; - case 0x7C: IABSX JMP CYC(6) break; // - case 0x7D: abx ADCc CYC(4) break; - case 0x7E: abx RORc CYC(6) break; - case 0x7F: $ NOP CYC(2) break; - case 0x80: REL BRA CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: $ IMM NOP CYC(2) break; - case 0x83: $ NOP CYC(2) break; - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: $ NOP CYC(2) break; - case 0x88: DEY CYC(2) break; - case 0x89: IMM BITI CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: $ NOP CYC(2) break; - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: $ NOP CYC(2) break; - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: izp STA CYC(5) break; - case 0x93: $ NOP CYC(2) break; - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: $ NOP CYC(2) break; - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: $ NOP CYC(2) break; - case 0x9C: ABS STZ CYC(4) break; - case 0x9D: abx STA CYC(5) break; - case 0x9E: abx STZ CYC(5) break; - case 0x9F: $ NOP CYC(2) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: $ NOP CYC(2) break; - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: $ NOP CYC(2) break; - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: $ NOP CYC(2) break; - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: $ NOP CYC(2) break; - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: izp LDA CYC(5) break; - case 0xB3: $ NOP CYC(2) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: $ NOP CYC(2) break; - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: $ NOP CYC(2) break; - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: $ NOP CYC(2) break; - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: $ IMM NOP CYC(2) break; - case 0xC3: $ NOP CYC(2) break; - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DECc CYC(5) break; - case 0xC7: $ NOP CYC(2) break; - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: $ NOP CYC(2) break; - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DECc CYC(5) break; - case 0xCF: $ NOP CYC(2) break; - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: izp CMP CYC(5) break; - case 0xD3: $ NOP CYC(2) break; - case 0xD4: $ zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DECc CYC(6) break; - case 0xD7: $ NOP CYC(2) break; - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: PHX CYC(3) break; - case 0xDB: $ NOP CYC(2) break; - case 0xDC: $ abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DECc CYC(6) break; - case 0xDF: $ NOP CYC(2) break; - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBCc CYC(6) break; - case 0xE2: $ IMM NOP CYC(2) break; - case 0xE3: $ NOP CYC(2) break; - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBCc CYC(3) break; - case 0xE6: ZPG INCc CYC(5) break; - case 0xE7: $ NOP CYC(2) break; - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBCc CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: $ NOP CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBCc CYC(4) break; - case 0xEE: ABS INCc CYC(6) break; - case 0xEF: $ NOP CYC(2) break; - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBCc CYC(5) break; - case 0xF2: izp SBCc CYC(5) break; - case 0xF3: $ NOP CYC(2) break; - case 0xF4: $ zpx NOP CYC(4) break; - case 0xF5: zpx SBCc CYC(4) break; - case 0xF6: zpx INCc CYC(6) break; - case 0xF7: $ NOP CYC(2) break; - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBCc CYC(4) break; - case 0xFA: PLX CYC(4) break; - case 0xFB: $ NOP CYC(2) break; - case 0xFC: $ abx NOP CYC(4) break; - case 0xFD: abx SBCc CYC(4) break; - case 0xFE: abx INCc CYC(6) break; - case 0xFF: $ NOP CYC(2) break; + case 0x00: BRK CYC(7) break; + case 0x01: idx ORA CYC(6) break; + case 0x02: $ IMM NOP CYC(2) break; + case 0x03: $ NOP CYC(1) break; + case 0x04: ZPG TSB CYC(5) break; + case 0x05: ZPG ORA CYC(3) break; + case 0x06: ZPG ASLc CYC(5) break; + case 0x07: $ NOP CYC(1) break; + case 0x08: PHP CYC(3) break; + case 0x09: IMM ORA CYC(2) break; + case 0x0A: asl CYC(2) break; + case 0x0B: $ NOP CYC(1) break; + case 0x0C: ABS TSB CYC(6) break; + case 0x0D: ABS ORA CYC(4) break; + case 0x0E: ABS ASLc CYC(6) break; + case 0x0F: $ NOP CYC(1) break; + case 0x10: REL BPL CYC(2) break; + case 0x11: INDY_OPT ORA CYC(5) break; + case 0x12: izp ORA CYC(5) break; + case 0x13: $ NOP CYC(1) break; + case 0x14: ZPG TRB CYC(5) break; + case 0x15: zpx ORA CYC(4) break; + case 0x16: zpx ASLc CYC(6) break; + case 0x17: $ NOP CYC(1) break; + case 0x18: CLC CYC(2) break; + case 0x19: ABSY_OPT ORA CYC(4) break; + case 0x1A: INA CYC(2) break; + case 0x1B: $ NOP CYC(1) break; + case 0x1C: ABS TRB CYC(6) break; + case 0x1D: ABSX_OPT ORA CYC(4) break; + case 0x1E: ABSX_OPT ASLc CYC(6) break; + case 0x1F: $ NOP CYC(1) break; + case 0x20: ABS JSR CYC(6) break; + case 0x21: idx AND CYC(6) break; + case 0x22: $ IMM NOP CYC(2) break; + case 0x23: $ NOP CYC(1) break; + case 0x24: ZPG BIT CYC(3) break; + case 0x25: ZPG AND CYC(3) break; + case 0x26: ZPG ROLc CYC(5) break; + case 0x27: $ NOP CYC(1) break; + case 0x28: PLP CYC(4) break; + case 0x29: IMM AND CYC(2) break; + case 0x2A: rol CYC(2) break; + case 0x2B: $ NOP CYC(1) break; + case 0x2C: ABS BIT CYC(4) break; + case 0x2D: ABS AND CYC(4) break; + case 0x2E: ABS ROLc CYC(6) break; + case 0x2F: $ NOP CYC(1) break; + case 0x30: REL BMI CYC(2) break; + case 0x31: INDY_OPT AND CYC(5) break; + case 0x32: izp AND CYC(5) break; + case 0x33: $ NOP CYC(1) break; + case 0x34: zpx BIT CYC(4) break; + case 0x35: zpx AND CYC(4) break; + case 0x36: zpx ROLc CYC(6) break; + case 0x37: $ NOP CYC(1) break; + case 0x38: SEC CYC(2) break; + case 0x39: ABSY_OPT AND CYC(4) break; + case 0x3A: DEA CYC(2) break; + case 0x3B: $ NOP CYC(1) break; + case 0x3C: ABSX_OPT BIT CYC(4) break; + case 0x3D: ABSX_OPT AND CYC(4) break; + case 0x3E: ABSX_OPT ROLc CYC(6) break; + case 0x3F: $ NOP CYC(1) break; + case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; + case 0x41: idx EOR CYC(6) break; + case 0x42: $ IMM NOP CYC(2) break; + case 0x43: $ NOP CYC(1) break; + case 0x44: $ ZPG NOP CYC(3) break; + case 0x45: ZPG EOR CYC(3) break; + case 0x46: ZPG LSRc CYC(5) break; + case 0x47: $ NOP CYC(1) break; + case 0x48: PHA CYC(3) break; + case 0x49: IMM EOR CYC(2) break; + case 0x4A: lsr CYC(2) break; + case 0x4B: $ NOP CYC(1) break; + case 0x4C: ABS JMP CYC(3) break; + case 0x4D: ABS EOR CYC(4) break; + case 0x4E: ABS LSRc CYC(6) break; + case 0x4F: $ NOP CYC(1) break; + case 0x50: REL BVC CYC(2) break; + case 0x51: INDY_OPT EOR CYC(5) break; + case 0x52: izp EOR CYC(5) break; + case 0x53: $ NOP CYC(1) break; + case 0x54: $ zpx NOP CYC(4) break; + case 0x55: zpx EOR CYC(4) break; + case 0x56: zpx LSRc CYC(6) break; + case 0x57: $ NOP CYC(1) break; + case 0x58: CLI CYC(2) break; + case 0x59: ABSY_OPT EOR CYC(4) break; + case 0x5A: PHY CYC(3) break; + case 0x5B: $ NOP CYC(1) break; + case 0x5C: $ ABS NOP CYC(8) break; + case 0x5D: ABSX_OPT EOR CYC(4) break; + case 0x5E: ABSX_OPT LSRc CYC(6) break; + case 0x5F: $ NOP CYC(1) break; + case 0x60: RTS CYC(6) break; + case 0x61: idx ADCc CYC(6) break; + case 0x62: $ IMM NOP CYC(2) break; + case 0x63: $ NOP CYC(1) break; + case 0x64: ZPG STZ CYC(3) break; + case 0x65: ZPG ADCc CYC(3) break; + case 0x66: ZPG RORc CYC(5) break; + case 0x67: $ NOP CYC(1) break; + case 0x68: PLA CYC(4) break; + case 0x69: IMM ADCc CYC(2) break; + case 0x6A: ror CYC(2) break; + case 0x6B: $ NOP CYC(1) break; + case 0x6C: IABS_CMOS JMP CYC(6) break; + case 0x6D: ABS ADCc CYC(4) break; + case 0x6E: ABS RORc CYC(6) break; + case 0x6F: $ NOP CYC(1) break; + case 0x70: REL BVS CYC(2) break; + case 0x71: INDY_OPT ADCc CYC(5) break; + case 0x72: izp ADCc CYC(5) break; + case 0x73: $ NOP CYC(1) break; + case 0x74: zpx STZ CYC(4) break; + case 0x75: zpx ADCc CYC(4) break; + case 0x76: zpx RORc CYC(6) break; + case 0x77: $ NOP CYC(1) break; + case 0x78: SEI CYC(2) break; + case 0x79: ABSY_OPT ADCc CYC(4) break; + case 0x7A: PLY CYC(4) break; + case 0x7B: $ NOP CYC(1) break; + case 0x7C: IABSX JMP CYC(6) break; + case 0x7D: ABSX_OPT ADCc CYC(4) break; + case 0x7E: ABSX_OPT RORc CYC(6) break; + case 0x7F: $ NOP CYC(1) break; + case 0x80: REL BRA CYC(2) break; + case 0x81: idx STA CYC(6) break; + case 0x82: $ IMM NOP CYC(2) break; + case 0x83: $ NOP CYC(1) break; + case 0x84: ZPG STY CYC(3) break; + case 0x85: ZPG STA CYC(3) break; + case 0x86: ZPG STX CYC(3) break; + case 0x87: $ NOP CYC(1) break; + case 0x88: DEY CYC(2) break; + case 0x89: IMM BITI CYC(2) break; + case 0x8A: TXA CYC(2) break; + case 0x8B: $ NOP CYC(1) break; + case 0x8C: ABS STY CYC(4) break; + case 0x8D: ABS STA CYC(4) break; + case 0x8E: ABS STX CYC(4) break; + case 0x8F: $ NOP CYC(1) break; + case 0x90: REL BCC CYC(2) break; + case 0x91: INDY_CONST STA CYC(6) break; + case 0x92: izp STA CYC(5) break; + case 0x93: $ NOP CYC(1) break; + case 0x94: zpx STY CYC(4) break; + case 0x95: zpx STA CYC(4) break; + case 0x96: zpy STX CYC(4) break; + case 0x97: $ NOP CYC(1) break; + case 0x98: TYA CYC(2) break; + case 0x99: ABSY_CONST STA CYC(5) break; + case 0x9A: TXS CYC(2) break; + case 0x9B: $ NOP CYC(1) break; + case 0x9C: ABS STZ CYC(4) break; + case 0x9D: ABSX_CONST STA CYC(5) break; + case 0x9E: ABSX_CONST STZ CYC(5) break; + case 0x9F: $ NOP CYC(1) break; + case 0xA0: IMM LDY CYC(2) break; + case 0xA1: idx LDA CYC(6) break; + case 0xA2: IMM LDX CYC(2) break; + case 0xA3: $ NOP CYC(1) break; + case 0xA4: ZPG LDY CYC(3) break; + case 0xA5: ZPG LDA CYC(3) break; + case 0xA6: ZPG LDX CYC(3) break; + case 0xA7: $ NOP CYC(1) break; + case 0xA8: TAY CYC(2) break; + case 0xA9: IMM LDA CYC(2) break; + case 0xAA: TAX CYC(2) break; + case 0xAB: $ NOP CYC(1) break; + case 0xAC: ABS LDY CYC(4) break; + case 0xAD: ABS LDA CYC(4) break; + case 0xAE: ABS LDX CYC(4) break; + case 0xAF: $ NOP CYC(1) break; + case 0xB0: REL BCS CYC(2) break; + case 0xB1: INDY_OPT LDA CYC(5) break; + case 0xB2: izp LDA CYC(5) break; + case 0xB3: $ NOP CYC(1) break; + case 0xB4: zpx LDY CYC(4) break; + case 0xB5: zpx LDA CYC(4) break; + case 0xB6: zpy LDX CYC(4) break; + case 0xB7: $ NOP CYC(1) break; + case 0xB8: CLV CYC(2) break; + case 0xB9: ABSY_OPT LDA CYC(4) break; + case 0xBA: TSX CYC(2) break; + case 0xBB: $ NOP CYC(1) break; + case 0xBC: ABSX_OPT LDY CYC(4) break; + case 0xBD: ABSX_OPT LDA CYC(4) break; + case 0xBE: ABSY_OPT LDX CYC(4) break; + case 0xBF: $ NOP CYC(1) break; + case 0xC0: IMM CPY CYC(2) break; + case 0xC1: idx CMP CYC(6) break; + case 0xC2: $ IMM NOP CYC(2) break; + case 0xC3: $ NOP CYC(1) break; + case 0xC4: ZPG CPY CYC(3) break; + case 0xC5: ZPG CMP CYC(3) break; + case 0xC6: ZPG DEC CYC(5) break; + case 0xC7: $ NOP CYC(1) break; + case 0xC8: INY CYC(2) break; + case 0xC9: IMM CMP CYC(2) break; + case 0xCA: DEX CYC(2) break; + case 0xCB: $ NOP CYC(1) break; + case 0xCC: ABS CPY CYC(4) break; + case 0xCD: ABS CMP CYC(4) break; + case 0xCE: ABS DEC CYC(6) break; + case 0xCF: $ NOP CYC(1) break; + case 0xD0: REL BNE CYC(2) break; + case 0xD1: INDY_OPT CMP CYC(5) break; + case 0xD2: izp CMP CYC(5) break; + case 0xD3: $ NOP CYC(1) break; + case 0xD4: $ zpx NOP CYC(4) break; + case 0xD5: zpx CMP CYC(4) break; + case 0xD6: zpx DEC CYC(6) break; + case 0xD7: $ NOP CYC(1) break; + case 0xD8: CLD CYC(2) break; + case 0xD9: ABSY_OPT CMP CYC(4) break; + case 0xDA: PHX CYC(3) break; + case 0xDB: $ NOP CYC(1) break; + case 0xDC: $ ABS LDD CYC(4) break; + case 0xDD: ABSX_OPT CMP CYC(4) break; + case 0xDE: ABSX_CONST DEC CYC(7) break; + case 0xDF: $ NOP CYC(1) break; + case 0xE0: IMM CPX CYC(2) break; + case 0xE1: idx SBCc CYC(6) break; + case 0xE2: $ IMM NOP CYC(2) break; + case 0xE3: $ NOP CYC(1) break; + case 0xE4: ZPG CPX CYC(3) break; + case 0xE5: ZPG SBCc CYC(3) break; + case 0xE6: ZPG INC CYC(5) break; + case 0xE7: $ NOP CYC(1) break; + case 0xE8: INX CYC(2) break; + case 0xE9: IMM SBCc CYC(2) break; + case 0xEA: NOP CYC(2) break; + case 0xEB: $ NOP CYC(1) break; + case 0xEC: ABS CPX CYC(4) break; + case 0xED: ABS SBCc CYC(4) break; + case 0xEE: ABS INC CYC(6) break; + case 0xEF: $ NOP CYC(1) break; + case 0xF0: REL BEQ CYC(2) break; + case 0xF1: INDY_OPT SBCc CYC(5) break; + case 0xF2: izp SBCc CYC(5) break; + case 0xF3: $ NOP CYC(1) break; + case 0xF4: $ zpx NOP CYC(4) break; + case 0xF5: zpx SBCc CYC(4) break; + case 0xF6: zpx INC CYC(6) break; + case 0xF7: $ NOP CYC(1) break; + case 0xF8: SED CYC(2) break; + case 0xF9: ABSY_OPT SBCc CYC(4) break; + case 0xFA: PLX CYC(4) break; + case 0xFB: $ NOP CYC(1) break; + case 0xFC: $ ABS LDD CYC(4) break; + case 0xFD: ABSX_OPT SBCc CYC(4) break; + case 0xFE: ABSX_CONST INC CYC(7) break; + case 0xFF: $ NOP CYC(1) break; } #undef $ } diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index bd55a933..7c3d34ed 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -18,8 +18,8 @@ along with AppleWin; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -typedef unsigned char u8; -typedef unsigned short u16; +typedef unsigned char u8; // TODO: change to uint8_t +typedef unsigned short u16; // TODO: change to uint16_t // return (x < 255) ? (x+1) : 255; inline u8 IncClamp8( u8 x ) @@ -37,43 +37,58 @@ inline u8 DecClamp8( u8 x ) return r; } +// TODO: Verify: RGBA or BGRA (.bmp format) // 0 A n/a // 1 B Exec // 2 G Read // 3 R Write -// RGBA r= write, g = read, b = pc -int g_aMemoryAccess[ 65536 ]; -u8 *g_pRead = 0; -u8 *g_pWrite = 0; -u8 *g_pExeec = 0; +// +// 0xAARRGGBB +// [0] B Exec +// [1] G Load +// [2] R Store +// [3] A n/a +// RGBA r = write, g = read, b = Program Counter +const int HEATMAP_W_MASK = 0x00FF0000; // Red Store +const int HEATMAP_R_MASK = 0x0000FF00; // Green Load +const int HEATMAP_X_MASK = 0x000000FF; // Blue Exec + + +// This is a memory heatmap +// FF = accessed on this clock cycle +// FE = accessed 1 clock cycles ago +// FD = accessed 2 clock cycles ago +// etc. +// Displayed as 256x256 64K memory access +int g_aMemoryHeatmap[ 65536 ]; // TODO: Change to int32_t + +#define HEATMAP_W(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_W_MASK +#define HEATMAP_R(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_R_MASK +#define HEATMAP_X(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_X_MASK #undef READ #define READ ReadByte( addr, uExecutedCycles ) inline u8 ReadByte( u16 addr, int uExecutedCycles ) { - (u8*) g_pRead = ((u8*)g_aMemoryAccess) + (addr * 4) + 3; - *g_pRead = IncClamp8( *g_pRead ); + // TODO: We should have a single g_bDebuggerActive so we can have a single implementation across ][+ //e + HEATMAP_R(addr); - return - ( \ - ((addr & 0xF000) == 0xC000) \ - ? IORead[(addr>>4) & 0xFF](regs.pc,addr,0,0,uExecutedCycles) \ - : *(mem+addr) \ - ); + return ((addr & 0xF000) == 0xC000) + ? IORead[(addr>>4) & 0xFF](regs.pc,addr,0,0,uExecutedCycles) + : *(mem+addr); } -#undef WRITE -#define WRITE(a) \ - (u8*) g_pWrite = ((u8*)g_aMemoryAccess) + (addr * 4) + 0; \ - *g_pWrite = DecClamp8( *g_pWrite ); \ - { \ - memdirty[addr >> 8] = 0xFF; \ - LPBYTE page = memwrite[addr >> 8]; \ - if (page) \ - *(page+(addr & 0xFF)) = (BYTE)(a); \ - else if ((addr & 0xF000) == 0xC000) \ - IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \ +#undef WRITE +#define WRITE(a) \ + HEATMAP_W(addr); \ + { \ + memdirty[addr >> 8] = 0xFF; \ + LPBYTE page = memwrite[addr >> 8]; \ + if (page) \ + *(page+(addr & 0xFF)) = (BYTE)(a); \ + else if ((addr & 0xF000) == 0xC000) \ + IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \ } #include "cpu/cpu_instructions.inl" @@ -97,7 +112,6 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) WORD val; AF_TO_EF ULONG uExecutedCycles = 0; - BOOL bSlowerOnPagecross = 0; // Set if opcode writes to memory (eg. ASL, STA) WORD base; g_bDebugBreakpointHit = 0; @@ -111,12 +125,14 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) ULONG uPreviousCycles = uExecutedCycles; // NTSC_END - if (g_ActiveCPU == CPU_Z80) + if (GetActiveCpu() == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) } else + HEATMAP_X( regs.pc ); + if (!Fetch(iOpcode, uExecutedCycles)) break; @@ -131,525 +147,264 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) { // TODO Optimization Note: ?? Move CYC(#) to array ?? -// Version 1 opcode: INV AM Instruction // Form1: INV=DebugBreak AM=AddressingMode -// INV Instruction // Form2: -//! ! ! ! ! ! // Tab-Stops -/* - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: INV IMM NOP CYC(2) break; - case 0x03: INV NOP CYC(2) break; - case 0x04: ZPG TSB CYC(5) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASL_CMOS CYC(5) break; - case 0x07: INV NOP CYC(2) break; - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: INV NOP CYC(2) break; - case 0x0C: ABS TSB CYC(6) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASL_CMOS CYC(6) break; - case 0x0F: INV NOP CYC(2) break; - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: izp ORA CYC(5) break; - case 0x13: INV NOP CYC(2) break; - case 0x14: ZPG TRB CYC(5) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASL_CMOS CYC(6) break; - case 0x17: INV NOP CYC(2) break; - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: INA CYC(2) break; - case 0x1B: INV NOP CYC(2) break; - case 0x1C: ABS TRB CYC(6) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASL_CMOS CYC(6) break; - case 0x1F: INV NOP CYC(2) break; - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: INV IMM NOP CYC(2) break; - case 0x23: INV NOP CYC(2) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROL_CMOS CYC(5) break; - case 0x27: INV NOP CYC(2) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: INV NOP CYC(2) break; - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROL_CMOS CYC(6) break; - case 0x2F: INV NOP CYC(2) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: izp AND CYC(5) break; - case 0x33: INV NOP CYC(2) break; - case 0x34: zpx BIT CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROL_CMOS CYC(6) break; - case 0x37: INV NOP CYC(2) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: DEA CYC(2) break; - case 0x3B: INV NOP CYC(2) break; - case 0x3C: abx BIT CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROL_CMOS CYC(6) break; - case 0x3F: INV NOP CYC(2) break; - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: INV IMM NOP CYC(2) break; - case 0x43: INV NOP CYC(2) break; - case 0x44: INV ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSR_CMOS CYC(5) break; - case 0x47: INV NOP CYC(2) break; - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: INV NOP CYC(2) break; - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSR_CMOS CYC(6) break; - case 0x4F: INV NOP CYC(2) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: izp EOR CYC(5) break; - case 0x53: INV NOP CYC(2) break; - case 0x54: INV zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSR_CMOS CYC(6) break; - case 0x57: INV NOP CYC(2) break; - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: PHY CYC(3) break; - case 0x5B: INV NOP CYC(2) break; - case 0x5C: INV abx NOP CYC(8) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSR_CMOS CYC(6) break; - case 0x5F: INV NOP CYC(2) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADC_CMOS CYC(6) break; - case 0x62: INV IMM NOP CYC(2) break; - case 0x63: INV NOP CYC(2) break; - case 0x64: ZPG STZ CYC(3) break; - case 0x65: ZPG ADC_CMOS CYC(3) break; - case 0x66: ZPG ROR_CMOS CYC(5) break; - case 0x67: INV NOP CYC(2) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADC_CMOS CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: INV NOP CYC(2) break; - case 0x6C: IABSCMOS JMP CYC(6) break; // 0x6C // 65c02 IABSCMOS JMP // 6502 IABSNMOS JMP - case 0x6D: ABS ADC_CMOS CYC(4) break; - case 0x6E: ABS ROR_CMOS CYC(6) break; - case 0x6F: INV NOP CYC(2) break; - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADC_CMOS CYC(5) break; - case 0x72: izp ADC_CMOS CYC(5) break; - case 0x73: INV NOP CYC(2) break; - case 0x74: zpx STZ CYC(4) break; - case 0x75: zpx ADC_CMOS CYC(4) break; - case 0x76: zpx ROR_CMOS CYC(6) break; - case 0x77: INV NOP CYC(2) break; - case 0x78: SEI CYC(2) break; - case 0x79: aby ADC_CMOS CYC(4) break; - case 0x7A: PLY CYC(4) break; - case 0x7B: INV NOP CYC(2) break; - case 0x7C: IABSX JMP CYC(6) break; // 0x7C // 65c02 IABSX JMP // 6502 ABSX NOP - case 0x7D: abx ADC_CMOS CYC(4) break; - case 0x7E: abx ROR_CMOS CYC(6) break; - case 0x7F: INV NOP CYC(2) break; - case 0x80: REL BRA CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: INV IMM NOP CYC(2) break; - case 0x83: INV NOP CYC(2) break; - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: INV NOP CYC(2) break; - case 0x88: DEY CYC(2) break; - case 0x89: IMM BITI CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: INV NOP CYC(2) break; - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: INV NOP CYC(2) break; - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: izp STA CYC(5) break; - case 0x93: INV NOP CYC(2) break; - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: INV NOP CYC(2) break; - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: INV NOP CYC(2) break; - case 0x9C: ABS STZ CYC(4) break; - case 0x9D: abx STA CYC(5) break; - case 0x9E: abx STZ CYC(5) break; - case 0x9F: INV NOP CYC(2) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: INV NOP CYC(2) break; - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: INV NOP CYC(2) break; - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: INV NOP CYC(2) break; - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: INV NOP CYC(2) break; - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: izp LDA CYC(5) break; - case 0xB3: INV NOP CYC(2) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: INV NOP CYC(2) break; - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: INV NOP CYC(2) break; - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: INV NOP CYC(2) break; - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: INV IMM NOP CYC(2) break; - case 0xC3: INV NOP CYC(2) break; - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DEC_CMOS CYC(5) break; - case 0xC7: INV NOP CYC(2) break; - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: INV NOP CYC(2) break; - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DEC_CMOS CYC(5) break; - case 0xCF: INV NOP CYC(2) break; - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: izp CMP CYC(5) break; - case 0xD3: INV NOP CYC(2) break; - case 0xD4: INV zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DEC_CMOS CYC(6) break; - case 0xD7: INV NOP CYC(2) break; - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: PHX CYC(3) break; - case 0xDB: INV NOP CYC(2) break; - case 0xDC: INV abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DEC_CMOS CYC(6) break; - case 0xDF: INV NOP CYC(2) break; - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBC_CMOS CYC(6) break; - case 0xE2: INV IMM NOP CYC(2) break; - case 0xE3: INV NOP CYC(2) break; - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBC_CMOS CYC(3) break; - case 0xE6: ZPG INC_CMOS CYC(5) break; - case 0xE7: INV NOP CYC(2) break; - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBC_CMOS CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: INV NOP CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBC_CMOS CYC(4) break; - case 0xEE: ABS INC_CMOS CYC(6) break; - case 0xEF: INV NOP CYC(2) break; - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBC_CMOS CYC(5) break; - case 0xF2: izp SBC_CMOS CYC(5) break; - case 0xF3: INV NOP CYC(2) break; - case 0xF4: INV zpx NOP CYC(4) break; - case 0xF5: zpx SBC_CMOS CYC(4) break; - case 0xF6: zpx INC_CMOS CYC(6) break; - case 0xF7: INV NOP CYC(2) break; - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBC_CMOS CYC(4) break; - case 0xFA: PLX CYC(4) break; - case 0xFB: INV NOP CYC(2) break; - case 0xFC: INV abx NOP CYC(4) break; - case 0xFD: abx SBC_CMOS CYC(4) break; - case 0xFE: abx INC_CMOS CYC(6) break; - case 0xFF: INV NOP CYC(2) break; -*/ -// Version 2 opcode: $ AM Instruction // $=DebugBreak AM=AddressingMode -//! ! ! ! ! ! // Tab-Stops - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: $ IMM NOP CYC(2) break; - case 0x03: $ NOP CYC(2) break; - case 0x04: ZPG TSB CYC(5) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASLc CYC(5) break; - case 0x07: $ NOP CYC(2) break; - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: $ NOP CYC(2) break; - case 0x0C: ABS TSB CYC(6) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASLc CYC(6) break; - case 0x0F: $ NOP CYC(2) break; - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: izp ORA CYC(5) break; - case 0x13: $ NOP CYC(2) break; - case 0x14: ZPG TRB CYC(5) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASLc CYC(6) break; - case 0x17: $ NOP CYC(2) break; - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: INA CYC(2) break; - case 0x1B: $ NOP CYC(2) break; - case 0x1C: ABS TRB CYC(6) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASLc CYC(6) break; - case 0x1F: $ NOP CYC(2) break; - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: $ IMM NOP CYC(2) break; - case 0x23: $ NOP CYC(2) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROLc CYC(5) break; - case 0x27: $ NOP CYC(2) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: $ NOP CYC(2) break; - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROLc CYC(6) break; - case 0x2F: $ NOP CYC(2) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: izp AND CYC(5) break; - case 0x33: $ NOP CYC(2) break; - case 0x34: zpx BIT CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROLc CYC(6) break; - case 0x37: $ NOP CYC(2) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: DEA CYC(2) break; - case 0x3B: $ NOP CYC(2) break; - case 0x3C: abx BIT CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROLc CYC(6) break; - case 0x3F: $ NOP CYC(2) break; - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: $ IMM NOP CYC(2) break; - case 0x43: $ NOP CYC(2) break; - case 0x44: $ ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSRc CYC(5) break; - case 0x47: $ NOP CYC(2) break; - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: $ NOP CYC(2) break; - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSRc CYC(6) break; - case 0x4F: $ NOP CYC(2) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: izp EOR CYC(5) break; - case 0x53: $ NOP CYC(2) break; - case 0x54: $ zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSRc CYC(6) break; - case 0x57: $ NOP CYC(2) break; - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: PHY CYC(3) break; - case 0x5B: $ NOP CYC(2) break; - case 0x5C: $ abx NOP CYC(8) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSRc CYC(6) break; - case 0x5F: $ NOP CYC(2) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADCc CYC(6) break; - case 0x62: $ IMM NOP CYC(2) break; - case 0x63: $ NOP CYC(2) break; - case 0x64: ZPG STZ CYC(3) break; - case 0x65: ZPG ADCc CYC(3) break; - case 0x66: ZPG RORc CYC(5) break; - case 0x67: $ NOP CYC(2) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADCc CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: $ NOP CYC(2) break; - case 0x6C: IABSCMOS JMP CYC(6) break; // 0x6C // 65c02 IABSCMOS JMP // 6502 IABSNMOS JMP - case 0x6D: ABS ADCc CYC(4) break; - case 0x6E: ABS RORc CYC(6) break; - case 0x6F: $ NOP CYC(2) break; - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADCc CYC(5) break; - case 0x72: izp ADCc CYC(5) break; - case 0x73: $ NOP CYC(2) break; - case 0x74: zpx STZ CYC(4) break; - case 0x75: zpx ADCc CYC(4) break; - case 0x76: zpx RORc CYC(6) break; - case 0x77: $ NOP CYC(2) break; - case 0x78: SEI CYC(2) break; - case 0x79: aby ADCc CYC(4) break; - case 0x7A: PLY CYC(4) break; - case 0x7B: $ NOP CYC(2) break; - case 0x7C: IABSX JMP CYC(6) break; // 0x7C // 65c02 IABSX JMP // 6502 ABSX NOP - case 0x7D: abx ADCc CYC(4) break; - case 0x7E: abx RORc CYC(6) break; - case 0x7F: $ NOP CYC(2) break; - case 0x80: REL BRA CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: $ IMM NOP CYC(2) break; - case 0x83: $ NOP CYC(2) break; - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: $ NOP CYC(2) break; - case 0x88: DEY CYC(2) break; - case 0x89: IMM BITI CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: $ NOP CYC(2) break; - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: $ NOP CYC(2) break; - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: izp STA CYC(5) break; - case 0x93: $ NOP CYC(2) break; - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: $ NOP CYC(2) break; - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: $ NOP CYC(2) break; - case 0x9C: ABS STZ CYC(4) break; - case 0x9D: abx STA CYC(5) break; - case 0x9E: abx STZ CYC(5) break; - case 0x9F: $ NOP CYC(2) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: $ NOP CYC(2) break; - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: $ NOP CYC(2) break; - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: $ NOP CYC(2) break; - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: $ NOP CYC(2) break; - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: izp LDA CYC(5) break; - case 0xB3: $ NOP CYC(2) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: $ NOP CYC(2) break; - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: $ NOP CYC(2) break; - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: $ NOP CYC(2) break; - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: $ IMM NOP CYC(2) break; - case 0xC3: $ NOP CYC(2) break; - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DECc CYC(5) break; - case 0xC7: $ NOP CYC(2) break; - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: $ NOP CYC(2) break; - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DECc CYC(5) break; - case 0xCF: $ NOP CYC(2) break; - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: izp CMP CYC(5) break; - case 0xD3: $ NOP CYC(2) break; - case 0xD4: $ zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DECc CYC(6) break; - case 0xD7: $ NOP CYC(2) break; - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: PHX CYC(3) break; - case 0xDB: $ NOP CYC(2) break; - case 0xDC: $ abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DECc CYC(6) break; - case 0xDF: $ NOP CYC(2) break; - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBCc CYC(6) break; - case 0xE2: $ IMM NOP CYC(2) break; - case 0xE3: $ NOP CYC(2) break; - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBCc CYC(3) break; - case 0xE6: ZPG INCc CYC(5) break; - case 0xE7: $ NOP CYC(2) break; - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBCc CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: $ NOP CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBCc CYC(4) break; - case 0xEE: ABS INCc CYC(6) break; - case 0xEF: $ NOP CYC(2) break; - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBCc CYC(5) break; - case 0xF2: izp SBCc CYC(5) break; - case 0xF3: $ NOP CYC(2) break; - case 0xF4: $ zpx NOP CYC(4) break; - case 0xF5: zpx SBCc CYC(4) break; - case 0xF6: zpx INCc CYC(6) break; - case 0xF7: $ NOP CYC(2) break; - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBCc CYC(4) break; - case 0xFA: PLX CYC(4) break; - case 0xFB: $ NOP CYC(2) break; - case 0xFC: $ abx NOP CYC(4) break; - case 0xFD: abx SBCc CYC(4) break; - case 0xFE: abx INCc CYC(6) break; - case 0xFF: $ NOP CYC(2) break; +// Version 2 opcode: $ AM Instruction // $=DebugBreak AM=AddressingMode +//! ! ! ! ! ! // Tab-Stops + case 0x00: BRK CYC(7) break; + case 0x01: idx ORA CYC(6) break; + case 0x02: $ IMM NOP CYC(2) break; + case 0x03: $ NOP CYC(2) break; + case 0x04: ZPG TSB CYC(5) break; + case 0x05: ZPG ORA CYC(3) break; + case 0x06: ZPG ASLc CYC(5) break; + case 0x07: $ NOP CYC(2) break; + case 0x08: PHP CYC(3) break; + case 0x09: IMM ORA CYC(2) break; + case 0x0A: asl CYC(2) break; + case 0x0B: $ NOP CYC(2) break; + case 0x0C: ABS TSB CYC(6) break; + case 0x0D: ABS ORA CYC(4) break; + case 0x0E: ABS ASLc CYC(6) break; + case 0x0F: $ NOP CYC(2) break; + case 0x10: REL BPL CYC(2) break; + case 0x11: INDY_OPT ORA CYC(5) break; + case 0x12: izp ORA CYC(5) break; + case 0x13: $ NOP CYC(2) break; + case 0x14: ZPG TRB CYC(5) break; + case 0x15: zpx ORA CYC(4) break; + case 0x16: zpx ASLc CYC(6) break; + case 0x17: $ NOP CYC(2) break; + case 0x18: CLC CYC(2) break; + case 0x19: ABSY_OPT ORA CYC(4) break; + case 0x1A: INA CYC(2) break; + case 0x1B: $ NOP CYC(2) break; + case 0x1C: ABS TRB CYC(6) break; + case 0x1D: ABSX_OPT ORA CYC(4) break; + case 0x1E: ABSX_OPT ASLc CYC(6) break; + case 0x1F: $ NOP CYC(2) break; + case 0x20: ABS JSR CYC(6) break; + case 0x21: idx AND CYC(6) break; + case 0x22: $ IMM NOP CYC(2) break; + case 0x23: $ NOP CYC(2) break; + case 0x24: ZPG BIT CYC(3) break; + case 0x25: ZPG AND CYC(3) break; + case 0x26: ZPG ROLc CYC(5) break; + case 0x27: $ NOP CYC(2) break; + case 0x28: PLP CYC(4) break; + case 0x29: IMM AND CYC(2) break; + case 0x2A: rol CYC(2) break; + case 0x2B: $ NOP CYC(2) break; + case 0x2C: ABS BIT CYC(4) break; + case 0x2D: ABS AND CYC(2) break; + case 0x2E: ABS ROLc CYC(6) break; + case 0x2F: $ NOP CYC(2) break; + case 0x30: REL BMI CYC(2) break; + case 0x31: INDY_OPT AND CYC(5) break; + case 0x32: izp AND CYC(5) break; + case 0x33: $ NOP CYC(2) break; + case 0x34: zpx BIT CYC(4) break; + case 0x35: zpx AND CYC(4) break; + case 0x36: zpx ROLc CYC(6) break; + case 0x37: $ NOP CYC(2) break; + case 0x38: SEC CYC(2) break; + case 0x39: ABSY_OPT AND CYC(4) break; + case 0x3A: DEA CYC(2) break; + case 0x3B: $ NOP CYC(2) break; + case 0x3C: ABSX_OPT BIT CYC(4) break; + case 0x3D: ABSX_OPT AND CYC(4) break; + case 0x3E: ABSX_OPT ROLc CYC(6) break; + case 0x3F: $ NOP CYC(2) break; + case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; + case 0x41: idx EOR CYC(6) break; + case 0x42: $ IMM NOP CYC(2) break; + case 0x43: $ NOP CYC(2) break; + case 0x44: $ ZPG NOP CYC(3) break; + case 0x45: ZPG EOR CYC(3) break; + case 0x46: ZPG LSRc CYC(5) break; + case 0x47: $ NOP CYC(2) break; + case 0x48: PHA CYC(3) break; + case 0x49: IMM EOR CYC(2) break; + case 0x4A: lsr CYC(2) break; + case 0x4B: $ NOP CYC(2) break; + case 0x4C: ABS JMP CYC(3) break; + case 0x4D: ABS EOR CYC(4) break; + case 0x4E: ABS LSRc CYC(6) break; + case 0x4F: $ NOP CYC(2) break; + case 0x50: REL BVC CYC(2) break; + case 0x51: INDY_OPT EOR CYC(5) break; + case 0x52: izp EOR CYC(5) break; + case 0x53: $ NOP CYC(2) break; + case 0x54: $ zpx NOP CYC(4) break; + case 0x55: zpx EOR CYC(4) break; + case 0x56: zpx LSRc CYC(6) break; + case 0x57: $ NOP CYC(2) break; + case 0x58: CLI CYC(2) break; + case 0x59: ABSY_OPT EOR CYC(4) break; + case 0x5A: PHY CYC(3) break; + case 0x5B: $ NOP CYC(2) break; + case 0x5C: $ ABSX_OPT NOP CYC(8) break; + case 0x5D: ABSX_OPT EOR CYC(4) break; + case 0x5E: ABSX_OPT LSRc CYC(6) break; + case 0x5F: $ NOP CYC(2) break; + case 0x60: RTS CYC(6) break; + case 0x61: idx ADCc CYC(6) break; + case 0x62: $ IMM NOP CYC(2) break; + case 0x63: $ NOP CYC(2) break; + case 0x64: ZPG STZ CYC(3) break; + case 0x65: ZPG ADCc CYC(3) break; + case 0x66: ZPG RORc CYC(5) break; + case 0x67: $ NOP CYC(2) break; + case 0x68: PLA CYC(4) break; + case 0x69: IMM ADCc CYC(2) break; + case 0x6A: ror CYC(2) break; + case 0x6B: $ NOP CYC(2) break; + case 0x6C: IABS_CMOS JMP CYC(6) break; + case 0x6D: ABS ADCc CYC(4) break; + case 0x6E: ABS RORc CYC(6) break; + case 0x6F: $ NOP CYC(2) break; + case 0x70: REL BVS CYC(2) break; + case 0x71: INDY_OPT ADCc CYC(5) break; + case 0x72: izp ADCc CYC(5) break; + case 0x73: $ NOP CYC(2) break; + case 0x74: zpx STZ CYC(4) break; + case 0x75: zpx ADCc CYC(4) break; + case 0x76: zpx RORc CYC(6) break; + case 0x77: $ NOP CYC(2) break; + case 0x78: SEI CYC(2) break; + case 0x79: ABSY_OPT ADCc CYC(4) break; + case 0x7A: PLY CYC(4) break; + case 0x7B: $ NOP CYC(2) break; + case 0x7C: IABSX JMP CYC(6) break; + case 0x7D: ABSX_OPT ADCc CYC(4) break; + case 0x7E: ABSX_OPT RORc CYC(6) break; + case 0x7F: $ NOP CYC(2) break; + case 0x80: REL BRA CYC(2) break; + case 0x81: idx STA CYC(6) break; + case 0x82: $ IMM NOP CYC(2) break; + case 0x83: $ NOP CYC(2) break; + case 0x84: ZPG STY CYC(3) break; + case 0x85: ZPG STA CYC(3) break; + case 0x86: ZPG STX CYC(3) break; + case 0x87: $ NOP CYC(2) break; + case 0x88: DEY CYC(2) break; + case 0x89: IMM BITI CYC(2) break; + case 0x8A: TXA CYC(2) break; + case 0x8B: $ NOP CYC(2) break; + case 0x8C: ABS STY CYC(4) break; + case 0x8D: ABS STA CYC(4) break; + case 0x8E: ABS STX CYC(4) break; + case 0x8F: $ NOP CYC(2) break; + case 0x90: REL BCC CYC(2) break; + case 0x91: INDY_CONST STA CYC(6) break; + case 0x92: izp STA CYC(5) break; + case 0x93: $ NOP CYC(2) break; + case 0x94: zpx STY CYC(4) break; + case 0x95: zpx STA CYC(4) break; + case 0x96: zpy STX CYC(4) break; + case 0x97: $ NOP CYC(2) break; + case 0x98: TYA CYC(2) break; + case 0x99: ABSY_CONST STA CYC(5) break; + case 0x9A: TXS CYC(2) break; + case 0x9B: $ NOP CYC(2) break; + case 0x9C: ABS STZ CYC(4) break; + case 0x9D: ABSX_CONST STA CYC(5) break; + case 0x9E: ABSX_CONST STZ CYC(5) break; + case 0x9F: $ NOP CYC(2) break; + case 0xA0: IMM LDY CYC(2) break; + case 0xA1: idx LDA CYC(6) break; + case 0xA2: IMM LDX CYC(2) break; + case 0xA3: $ NOP CYC(2) break; + case 0xA4: ZPG LDY CYC(3) break; + case 0xA5: ZPG LDA CYC(3) break; + case 0xA6: ZPG LDX CYC(3) break; + case 0xA7: $ NOP CYC(2) break; + case 0xA8: TAY CYC(2) break; + case 0xA9: IMM LDA CYC(2) break; + case 0xAA: TAX CYC(2) break; + case 0xAB: $ NOP CYC(2) break; + case 0xAC: ABS LDY CYC(4) break; + case 0xAD: ABS LDA CYC(4) break; + case 0xAE: ABS LDX CYC(4) break; + case 0xAF: $ NOP CYC(2) break; + case 0xB0: REL BCS CYC(2) break; + case 0xB1: INDY_OPT LDA CYC(5) break; + case 0xB2: izp LDA CYC(5) break; + case 0xB3: $ NOP CYC(2) break; + case 0xB4: zpx LDY CYC(4) break; + case 0xB5: zpx LDA CYC(4) break; + case 0xB6: zpy LDX CYC(4) break; + case 0xB7: $ NOP CYC(2) break; + case 0xB8: CLV CYC(2) break; + case 0xB9: ABSY_OPT LDA CYC(4) break; + case 0xBA: TSX CYC(2) break; + case 0xBB: $ NOP CYC(2) break; + case 0xBC: ABSX_OPT LDY CYC(4) break; + case 0xBD: ABSX_OPT LDA CYC(4) break; + case 0xBE: ABSY_OPT LDX CYC(4) break; + case 0xBF: $ NOP CYC(2) break; + case 0xC0: IMM CPY CYC(2) break; + case 0xC1: idx CMP CYC(6) break; + case 0xC2: $ IMM NOP CYC(2) break; + case 0xC3: $ NOP CYC(2) break; + case 0xC4: ZPG CPY CYC(3) break; + case 0xC5: ZPG CMP CYC(3) break; + case 0xC6: ZPG DEC CYC(5) break; + case 0xC7: $ NOP CYC(2) break; + case 0xC8: INY CYC(2) break; + case 0xC9: IMM CMP CYC(2) break; + case 0xCA: DEX CYC(2) break; + case 0xCB: $ NOP CYC(2) break; + case 0xCC: ABS CPY CYC(4) break; + case 0xCD: ABS CMP CYC(4) break; + case 0xCE: ABS DEC CYC(6) break; + case 0xCF: $ NOP CYC(2) break; + case 0xD0: REL BNE CYC(2) break; + case 0xD1: INDY_OPT CMP CYC(5) break; + case 0xD2: izp CMP CYC(5) break; + case 0xD3: $ NOP CYC(2) break; + case 0xD4: $ zpx NOP CYC(4) break; + case 0xD5: zpx CMP CYC(4) break; + case 0xD6: zpx DEC CYC(6) break; + case 0xD7: $ NOP CYC(2) break; + case 0xD8: CLD CYC(2) break; + case 0xD9: ABSY_OPT CMP CYC(4) break; + case 0xDA: PHX CYC(3) break; + case 0xDB: $ NOP CYC(2) break; + case 0xDC: $ ABSX_OPT NOP CYC(4) break; + case 0xDD: ABSX_OPT CMP CYC(4) break; + case 0xDE: ABSX_CONST DEC CYC(7) break; + case 0xDF: $ NOP CYC(2) break; + case 0xE0: IMM CPX CYC(2) break; + case 0xE1: idx SBCc CYC(6) break; + case 0xE2: $ IMM NOP CYC(2) break; + case 0xE3: $ NOP CYC(2) break; + case 0xE4: ZPG CPX CYC(3) break; + case 0xE5: ZPG SBCc CYC(3) break; + case 0xE6: ZPG INC CYC(5) break; + case 0xE7: $ NOP CYC(2) break; + case 0xE8: INX CYC(2) break; + case 0xE9: IMM SBCc CYC(2) break; + case 0xEA: NOP CYC(2) break; + case 0xEB: $ NOP CYC(2) break; + case 0xEC: ABS CPX CYC(4) break; + case 0xED: ABS SBCc CYC(4) break; + case 0xEE: ABS INC CYC(6) break; + case 0xEF: $ NOP CYC(2) break; + case 0xF0: REL BEQ CYC(2) break; + case 0xF1: INDY_OPT SBCc CYC(5) break; + case 0xF2: izp SBCc CYC(5) break; + case 0xF3: $ NOP CYC(2) break; + case 0xF4: $ zpx NOP CYC(4) break; + case 0xF5: zpx SBCc CYC(4) break; + case 0xF6: zpx INC CYC(6) break; + case 0xF7: $ NOP CYC(2) break; + case 0xF8: SED CYC(2) break; + case 0xF9: ABSY_OPT SBCc CYC(4) break; + case 0xFA: PLX CYC(4) break; + case 0xFB: $ NOP CYC(2) break; + case 0xFC: $ ABSX_OPT NOP CYC(4) break; + case 0xFD: ABSX_OPT SBCc CYC(4) break; + case 0xFE: ABSX_CONST INC CYC(7) break; + case 0xFF: $ NOP CYC(2) break; } #undef $ diff --git a/source/CPU/cpu_general.inl b/source/CPU/cpu_general.inl index 25f7086e..4d565efb 100644 --- a/source/CPU/cpu_general.inl +++ b/source/CPU/cpu_general.inl @@ -73,6 +73,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \ } +#define ON_PAGECROSS_REPLACE_HI_ADDR if ((base ^ addr) >> 8) {addr = (val<<8) | (addr&0xff);} /* GH#282 */ + // // ExtraCycles: @@ -89,10 +91,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -#define CHECK_PAGE_CHANGE if (bSlowerOnPagecross) { \ - if ((base ^ addr) & 0xFF00) \ - uExtraCycles=1; \ - } +// TODO Optimization Note: uExtraCycles = ((base ^ addr) >> 8) & 1; +#define CHECK_PAGE_CHANGE if ((base ^ addr) & 0xFF00) \ + uExtraCycles=1; /**************************************************************************** * @@ -102,53 +103,71 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ABS addr = *(LPWORD)(mem+regs.pc); regs.pc += 2; #define IABSX addr = *(LPWORD)(mem+(*(LPWORD)(mem+regs.pc))+(WORD)regs.x); regs.pc += 2; -#define ABSX base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; CHECK_PAGE_CHANGE; -#define ABSY base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.y; regs.pc += 2; CHECK_PAGE_CHANGE; -// TODO Optimization Note: uExtraCycles = ((base & 0xFF) + 1) >> 8; -#define IABSCMOS base = *(LPWORD)(mem+regs.pc); \ + +// Optimised for page-cross +#define ABSX_OPT base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; CHECK_PAGE_CHANGE; +// Not optimised for page-cross +#define ABSX_CONST base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; + +// Optimised for page-cross +#define ABSY_OPT base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.y; regs.pc += 2; CHECK_PAGE_CHANGE; +// Not optimised for page-cross +#define ABSY_CONST base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.y; regs.pc += 2; + +// TODO Optimization Note (just for IABSCMOS): uExtraCycles = ((base & 0xFF) + 1) >> 8; +#define IABS_CMOS base = *(LPWORD)(mem+regs.pc); \ addr = *(LPWORD)(mem+base); \ if ((base & 0xFF) == 0xFF) uExtraCycles=1; \ regs.pc += 2; -#define IABSNMOS base = *(LPWORD)(mem+regs.pc); \ +#define IABS_NMOS base = *(LPWORD)(mem+regs.pc); \ if ((base & 0xFF) == 0xFF) \ addr = *(mem+base)+((WORD)*(mem+(base&0xFF00))<<8);\ - else \ + else \ addr = *(LPWORD)(mem+base); \ regs.pc += 2; + #define IMM addr = regs.pc++; + #define INDX base = ((*(mem+regs.pc++))+regs.x) & 0xFF; \ if (base == 0xFF) \ addr = *(mem+0xFF)+(((WORD)*mem)<<8); \ else \ addr = *(LPWORD)(mem+base); -#define INDY if (*(mem+regs.pc) == 0xFF) \ + +// Optimised for page-cross +#define INDY_OPT if (*(mem+regs.pc) == 0xFF) /*incurs an extra cycle for page-crossing*/ \ base = *(mem+0xFF)+(((WORD)*mem)<<8); \ else \ base = *(LPWORD)(mem+*(mem+regs.pc)); \ regs.pc++; \ addr = base+(WORD)regs.y; \ CHECK_PAGE_CHANGE; +// Not optimised for page-cross +#define INDY_CONST if (*(mem+regs.pc) == 0xFF) /*no extra cycle for page-crossing*/ \ + base = *(mem+0xFF)+(((WORD)*mem)<<8); \ + else \ + base = *(LPWORD)(mem+*(mem+regs.pc)); \ + regs.pc++; \ + addr = base+(WORD)regs.y; + #define IZPG base = *(mem+regs.pc++); \ if (base == 0xFF) \ addr = *(mem+0xFF)+(((WORD)*mem)<<8); \ else \ addr = *(LPWORD)(mem+base); + #define REL addr = (signed char)*(mem+regs.pc++); // TODO Optimization Note: // . Opcodes that generate zero-page addresses can't be accessing $C000..$CFFF // so they could be paired with special READZP/WRITEZP macros (instead of READ/WRITE) -#define ZPG addr = *(mem+regs.pc++); +#define ZPG addr = *(mem+regs.pc++); #define ZPGX addr = ((*(mem+regs.pc++))+regs.x) & 0xFF; #define ZPGY addr = ((*(mem+regs.pc++))+regs.y) & 0xFF; // Tidy 3 char addressing modes to keep the opcode table visually aligned, clean, and readable. -#undef abx -#undef abx -#undef aby #undef asl #undef idx -#undef idy #undef imm #undef izp #undef lsr @@ -158,11 +177,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef zpx #undef zpy -#define abx ABSX -#define aby ABSY #define asl ASLA // Arithmetic Shift Left #define idx INDX -#define idy INDY #define imm IMM #define izp IZPG #define lsr LSRA // Logical Shift Right @@ -171,6 +187,3 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ror RORA // Rotate Right #define zpx ZPGX #define zpy ZPGY -// 0x6C // 65c02 IABSCMOS JMP // 6502 IABSNMOS JMP -// 0x7C IABSX - diff --git a/source/CPU/cpu_instructions.inl b/source/CPU/cpu_instructions.inl index 84e68bae..8daa6178 100644 --- a/source/CPU/cpu_instructions.inl +++ b/source/CPU/cpu_instructions.inl @@ -68,15 +68,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef CPY #undef DCM #undef DEA -#undef DEC_NMOS -#undef DEC_CMOS +#undef DEC #undef DEX #undef DEY #undef EOR #undef HLT #undef INA -#undef INC_NMOS -#undef INC_CMOS +#undef INC #undef INS #undef INX #undef INY @@ -139,8 +137,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef ADCn #undef ASLn -#undef DECn -#undef INCn #undef LSRn #undef ROLn #undef RORn @@ -148,8 +144,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ADCn ADC_NMOS #define ASLn ASL_NMOS -#define DECn DEC_NMOS -#define INCn INC_NMOS #define LSRn LSR_NMOS #define ROLn ROL_NMOS #define RORn ROR_NMOS @@ -159,8 +153,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef ADCc #undef ASLc -#undef DECc -#undef INCc #undef LSRc #undef ROLc #undef RORc @@ -168,8 +160,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ADCc ADC_CMOS #define ASLc ASL_CMOS -#define DECc DEC_CMOS -#define INCc INC_CMOS #define LSRc LSR_CMOS #define ROLc ROL_CMOS #define RORc ROR_CMOS @@ -177,7 +167,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ========== -#define ADC_NMOS bSlowerOnPagecross = 1; \ +#define ADC_NMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ if (regs.ps & AF_DECIMAL) { \ val = (regs.a & 0x0F) + (temp & 0x0F) + flagc; \ @@ -203,7 +193,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA regs.a = val & 0xFF; \ SETNZ(regs.a); \ } -#define ADC_CMOS bSlowerOnPagecross = 1; \ +#define ADC_CMOS /*bSlowerOnPagecross = 1*/; \ temp = READ; \ flagv = !((regs.a ^ temp) & 0x80); \ if (regs.ps & AF_DECIMAL) { \ @@ -242,7 +232,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagn = 0; \ regs.a >>= 1; \ SETZ(regs.a) -#define AND bSlowerOnPagecross = 1; \ +#define AND /*bSlowerOnPagecross = 1;*/ \ regs.a &= READ; \ SETNZ(regs.a) #define ANC regs.a &= READ; \ @@ -274,12 +264,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagv = ((val & 0x40) ^ ((val & 0x20) << 1)); \ regs.a = (val & 0xFF); \ } -#define ASL_NMOS bSlowerOnPagecross = 0; \ +#define ASL_NMOS /*bSlowerOnPagecross = 0;*/ \ val = READ << 1; \ flagc = (val > 0xFF); \ SETNZ(val) \ WRITE(val) -#define ASL_CMOS bSlowerOnPagecross = 1; \ +#define ASL_CMOS /*bSlowerOnPagecross = 1*/; \ val = READ << 1; \ flagc = (val > 0xFF); \ SETNZ(val) \ @@ -288,21 +278,22 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (val > 0xFF); \ SETNZ(val) \ regs.a = (BYTE)val; -#define ASO bSlowerOnPagecross = 0; \ +#define ASO /*bSlowerOnPagecross = 0;*/ \ val = READ << 1; \ flagc = (val > 0xFF); \ WRITE(val) \ regs.a |= val; \ SETNZ(regs.a) -#define AXA bSlowerOnPagecross = 0;/*FIXME: $93 case is still unclear*/ \ +#define AXA /*bSlowerOnPagecross = 0;*/ \ val = regs.a & regs.x & (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) -#define AXS bSlowerOnPagecross = 0; \ +#define AXS /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.a & regs.x) #define BCC if (!flagc) BRANCH_TAKEN; #define BCS if ( flagc) BRANCH_TAKEN; #define BEQ if ( flagz) BRANCH_TAKEN; -#define BIT bSlowerOnPagecross = 1; \ +#define BIT /*bSlowerOnPagecross = 1;*/ \ val = READ; \ flagz = !(regs.a & val); \ flagn = val & 0x80; \ @@ -325,7 +316,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define CLD regs.ps &= ~AF_DECIMAL; #define CLI regs.ps &= ~AF_INTERRUPT; #define CLV flagv = 0; -#define CMP bSlowerOnPagecross = 1; \ +#define CMP /*bSlowerOnPagecross = 1;*/ \ val = READ; \ flagc = (regs.a >= val); \ val = regs.a-val; \ @@ -338,7 +329,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (regs.y >= val); \ val = regs.y-val; \ SETNZ(val) -#define DCM bSlowerOnPagecross = 0; \ +#define DCM /*bSlowerOnPagecross = 0;*/ \ val = READ-1; \ WRITE(val) \ flagc = (regs.a >= val); \ @@ -346,11 +337,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA SETNZ(val) #define DEA --regs.a; \ SETNZ(regs.a) -#define DEC_NMOS bSlowerOnPagecross = 0; \ - val = READ-1; \ - SETNZ(val) \ - WRITE(val) -#define DEC_CMOS bSlowerOnPagecross = 1; \ +#define DEC /*bSlowerOnPagecross = 0;*/ \ val = READ-1; \ SETNZ(val) \ WRITE(val) @@ -358,22 +345,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA SETNZ(regs.x) #define DEY --regs.y; \ SETNZ(regs.y) -#define EOR bSlowerOnPagecross = 1; \ +#define EOR /*bSlowerOnPagecross = 1;*/ \ regs.a ^= READ; \ SETNZ(regs.a) #define HLT regs.bJammed = 1; \ --regs.pc; #define INA ++regs.a; \ SETNZ(regs.a) -#define INC_NMOS bSlowerOnPagecross = 0; \ +#define INC /*bSlowerOnPagecross = 0;*/ \ val = READ+1; \ SETNZ(val) \ WRITE(val) -#define INC_CMOS bSlowerOnPagecross = 1; \ - val = READ+1; \ - SETNZ(val) \ - WRITE(val) -#define INS bSlowerOnPagecross = 0; \ +#define INS /*bSlowerOnPagecross = 0;*/ \ val = READ+1; \ WRITE(val) \ temp = val; \ @@ -408,38 +391,40 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA PUSH(regs.pc >> 8) \ PUSH(regs.pc & 0xFF) \ regs.pc = addr; -#define LAS bSlowerOnPagecross = 1; \ +#define LAS /*bSlowerOnPagecross = 1*/; \ val = (BYTE)(READ & regs.sp); \ regs.a = regs.x = (BYTE) val; \ regs.sp = val | 0x100; \ SETNZ(val) -#define LAX bSlowerOnPagecross = 1; \ +#define LAX /*bSlowerOnPagecross = 1;*/ \ regs.a = regs.x = READ; \ SETNZ(regs.a) -#define LDA bSlowerOnPagecross = 1; \ +#define LDA /*bSlowerOnPagecross = 1;*/ \ regs.a = READ; \ SETNZ(regs.a) -#define LDX bSlowerOnPagecross = 1; \ +#define LDD /*Undocumented 65C02: LoaD and Discard*/ \ + READ; +#define LDX /*bSlowerOnPagecross = 1;*/ \ regs.x = READ; \ SETNZ(regs.x) -#define LDY bSlowerOnPagecross = 1; \ +#define LDY /*bSlowerOnPagecross = 1;*/ \ regs.y = READ; \ SETNZ(regs.y) -#define LSE bSlowerOnPagecross = 0; \ +#define LSE /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagc = (val & 1); \ val >>= 1; \ WRITE(val) \ regs.a ^= val; \ SETNZ(regs.a) -#define LSR_NMOS bSlowerOnPagecross = 0; \ +#define LSR_NMOS /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagc = (val & 1); \ flagn = 0; \ val >>= 1; \ SETZ(val) \ WRITE(val) -#define LSR_CMOS bSlowerOnPagecross = 1; \ +#define LSR_CMOS /*bSlowerOnPagecross = 1;*/ \ val = READ; \ flagc = (val & 1); \ flagn = 0; \ @@ -450,12 +435,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagn = 0; \ regs.a >>= 1; \ SETZ(regs.a) -#define NOP bSlowerOnPagecross = 1; +#define NOP /*bSlowerOnPagecross = 1;*/ #define OAL regs.a |= 0xEE; \ regs.a &= READ; \ regs.x = regs.a; \ SETNZ(regs.a) -#define ORA bSlowerOnPagecross = 1; \ +#define ORA /*bSlowerOnPagecross = 1;*/ \ regs.a |= READ; \ SETNZ(regs.a) #define PHA PUSH(regs.a) @@ -471,18 +456,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA SETNZ(regs.x) #define PLY regs.y = POP; \ SETNZ(regs.y) -#define RLA bSlowerOnPagecross = 0; \ +#define RLA /*bSlowerOnPagecross = 0;*/ \ val = (READ << 1) | flagc; \ flagc = (val > 0xFF); \ WRITE(val) \ regs.a &= val; \ SETNZ(regs.a) -#define ROL_NMOS bSlowerOnPagecross = 0; \ +#define ROL_NMOS /*bSlowerOnPagecross = 0;*/ \ val = (READ << 1) | flagc; \ flagc = (val > 0xFF); \ SETNZ(val) \ WRITE(val) -#define ROL_CMOS bSlowerOnPagecross = 1; \ +#define ROL_CMOS /*bSlowerOnPagecross = 1;*/ \ val = (READ << 1) | flagc; \ flagc = (val > 0xFF); \ SETNZ(val) \ @@ -491,13 +476,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (val > 0xFF); \ regs.a = val & 0xFF; \ SETNZ(regs.a); -#define ROR_NMOS bSlowerOnPagecross = 0; \ +#define ROR_NMOS /*bSlowerOnPagecross = 0;*/ \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = (temp & 1); \ SETNZ(val) \ WRITE(val) -#define ROR_CMOS bSlowerOnPagecross = 1; \ +#define ROR_CMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = (temp & 1); \ @@ -507,7 +492,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (regs.a & 1); \ regs.a = val & 0xFF; \ SETNZ(regs.a) -#define RRA bSlowerOnPagecross = 0; \ +#define RRA /*bSlowerOnPagecross = 0;*/ \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = (temp & 1); \ @@ -549,10 +534,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (temp >= val); \ regs.x = temp-val; \ SETNZ(regs.x) -#define SAY bSlowerOnPagecross = 0; \ +#define SAY /*bSlowerOnPagecross = 0;*/ \ val = regs.y & (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) -#define SBC_NMOS bSlowerOnPagecross = 1; \ +#define SBC_NMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ temp2 = regs.a - temp - !flagc; \ if (regs.ps & AF_DECIMAL) { \ @@ -576,7 +562,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA regs.a = val & 0xFF; \ SETNZ(regs.a); \ } -#define SBC_CMOS bSlowerOnPagecross = 1; \ +#define SBC_CMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ flagv = ((regs.a ^ temp) & 0x80); \ if (regs.ps & AF_DECIMAL) { \ @@ -622,29 +608,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SEC flagc = 1; #define SED regs.ps |= AF_DECIMAL; #define SEI regs.ps |= AF_INTERRUPT; -#define STA bSlowerOnPagecross = 0; \ +#define STA /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.a) -#define STX bSlowerOnPagecross = 0; \ +#define STX /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.x) -#define STY bSlowerOnPagecross = 0; \ +#define STY /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.y) -#define STZ bSlowerOnPagecross = 0; \ +#define STZ /*bSlowerOnPagecross = 0;*/ \ WRITE(0) -#define TAS bSlowerOnPagecross = 0; \ +#define TAS /*bSlowerOnPagecross = 0;*/ \ val = regs.a & regs.x; \ regs.sp = 0x100 | val; \ val &= (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) #define TAX regs.x = regs.a; \ SETNZ(regs.x) #define TAY regs.y = regs.a; \ SETNZ(regs.y) -#define TRB bSlowerOnPagecross = 0; \ +#define TRB /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagz = !(regs.a & val); \ val &= ~regs.a; \ WRITE(val) -#define TSB bSlowerOnPagecross = 0; \ +#define TSB /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagz = !(regs.a & val); \ val |= regs.a; \ @@ -659,7 +646,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define XAA regs.a = regs.x; \ regs.a &= READ; \ SETNZ(regs.a) -#define XAS bSlowerOnPagecross = 0; \ +#define XAS /*bSlowerOnPagecross = 0;*/ \ val = regs.x & (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) - diff --git a/source/Common.h b/source/Common.h index f89db922..2bc2a071 100644 --- a/source/Common.h +++ b/source/Common.h @@ -70,6 +70,7 @@ enum AppMode_e // Configuration #define REG_CONFIG "Configuration" #define REGVALUE_APPLE2_TYPE "Apple2 Type" +#define REGVALUE_CPU_TYPE "CPU Type" #define REGVALUE_OLD_APPLE2_TYPE "Computer Emulation" // Deprecated #define REGVALUE_CONFIRM_REBOOT "Confirm Reboot" // Added at 1.24.1 PageConfig #define REGVALUE_SPKR_VOLUME "Speaker Volume" @@ -165,7 +166,7 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE}; #define IS_APPLE2C (g_Apple2Type & APPLE2C_MASK) #define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK) -// NB. These get persisted to the Registry, so don't change the values for these enums! +// NB. These get persisted to the Registry & save-state file, so don't change the values for these enums! enum eApple2Type { A2TYPE_APPLE2=0, A2TYPE_APPLE2PLUS, diff --git a/source/Configuration/Config.h b/source/Configuration/Config.h index 2915d6cb..36be83af 100644 --- a/source/Configuration/Config.h +++ b/source/Configuration/Config.h @@ -1,6 +1,7 @@ #pragma once #include "..\AppleWin.h" +#include "..\CPU.h" #include "..\Disk.h" // BOOL enhancedisk #include "..\HardDisk.h" // HD_CardIsEnabled() @@ -8,13 +9,15 @@ class CConfigNeedingRestart { public: CConfigNeedingRestart(UINT bEnableTheFreezesF8Rom = false) : - m_Apple2Type(g_Apple2Type), + m_Apple2Type( GetApple2Type() ), + m_CpuType( GetMainCpu() ), m_bEnhanceDisk(enhancedisk), m_uSaveLoadStateMsg(0) { m_bEnableHDD = HD_CardIsEnabled(); m_bEnableTheFreezesF8Rom = bEnableTheFreezesF8Rom; memset(&m_Slot, 0, sizeof(m_Slot)); + m_SlotAux = CT_Empty; m_Slot[4] = g_Slot4; m_Slot[5] = g_Slot5; } @@ -22,6 +25,7 @@ public: const CConfigNeedingRestart& operator= (const CConfigNeedingRestart& other) { m_Apple2Type = other.m_Apple2Type; + m_CpuType = other.m_CpuType; memcpy(m_Slot, other.m_Slot, sizeof(m_Slot)); m_bEnhanceDisk = other.m_bEnhanceDisk; m_bEnableHDD = other.m_bEnableHDD; @@ -33,6 +37,7 @@ public: bool operator== (const CConfigNeedingRestart& other) const { return m_Apple2Type == other.m_Apple2Type && + m_CpuType == other.m_CpuType && memcmp(m_Slot, other.m_Slot, sizeof(m_Slot)) == 0 && m_bEnhanceDisk == other.m_bEnhanceDisk && m_bEnableHDD == other.m_bEnableHDD && @@ -46,7 +51,9 @@ public: } eApple2Type m_Apple2Type; + eCpuType m_CpuType; SS_CARDTYPE m_Slot[NUM_SLOTS]; // 0..7 + SS_CARDTYPE m_SlotAux; BOOL m_bEnhanceDisk; bool m_bEnableHDD; UINT m_bEnableTheFreezesF8Rom; diff --git a/source/Configuration/IPropertySheet.h b/source/Configuration/IPropertySheet.h index c25b2ce8..b0312009 100644 --- a/source/Configuration/IPropertySheet.h +++ b/source/Configuration/IPropertySheet.h @@ -1,10 +1,13 @@ #pragma once +class CConfigNeedingRestart; + __interface IPropertySheet { void Init(void); DWORD GetVolumeMax(void); // TODO:TC: Move out of here bool SaveStateSelectImage(HWND hWindow, bool bSave); // TODO:TC: Move out of here + void ApplyNewConfig(const CConfigNeedingRestart& ConfigNew, const CConfigNeedingRestart& ConfigOld); UINT GetScrollLockToggle(void); void SetScrollLockToggle(UINT uValue); diff --git a/source/Configuration/PageAdvanced.cpp b/source/Configuration/PageAdvanced.cpp index de469041..c50cf5c7 100644 --- a/source/Configuration/PageAdvanced.cpp +++ b/source/Configuration/PageAdvanced.cpp @@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "StdAfx.h" -#include "..\Structs.h" #include "..\Common.h" #include "..\ParallelPrinter.h" diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp index a5c47884..f525fc8c 100644 --- a/source/Configuration/PageConfig.cpp +++ b/source/Configuration/PageConfig.cpp @@ -129,6 +129,7 @@ BOOL CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM const DWORD NewComputerMenuItem = (DWORD) SendDlgItemMessage(hWnd, IDC_COMPUTER, CB_GETCURSEL, 0, 0); const eApple2Type NewApple2Type = GetApple2Type(NewComputerMenuItem); m_PropertySheetHelper.GetConfigNew().m_Apple2Type = NewApple2Type; + m_PropertySheetHelper.GetConfigNew().m_CpuType = ProbeMainCpuDefault(NewApple2Type); } break; diff --git a/source/Configuration/PageInput.cpp b/source/Configuration/PageInput.cpp index 9326afee..7bd0a20b 100644 --- a/source/Configuration/PageInput.cpp +++ b/source/Configuration/PageInput.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "StdAfx.h" -#include "..\Structs.h" +#include "..\SaveState_Structs_common.h" #include "..\Common.h" #include "..\Keyboard.h" @@ -214,12 +214,12 @@ void CPageInput::DlgOK(HWND hWnd) if (JoySetEmulationType(hWnd, m_nJoy0ChoiceTranlationTbl[uNewJoyType0], JN_JOYSTICK0, bIsSlot4Mouse)) { - REGSAVE(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), joytype[0]); + REGSAVE(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), JoyGetJoyType(0)); } if (JoySetEmulationType(hWnd, m_nJoy1ChoiceTranlationTbl[uNewJoyType1], JN_JOYSTICK1, bIsSlot4Mouse)) { - REGSAVE(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), joytype[1]); + REGSAVE(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), JoyGetJoyType(1)); } JoySetTrim((short)SendDlgItemMessage(hWnd, IDC_SPIN_XTRIM, UDM_GETPOS, 0, 0), true); @@ -305,7 +305,7 @@ void CPageInput::InitJoystickChoices(HWND hWnd, int nJoyNum, int nIdcValue) for(UINT i=nJC_KEYBD_CURSORS; i "file" + ".aws.yaml" + else + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile], szAWS_EXT3); // "file" += ".aws.yaml" + } + else if ((uStrLenFile <= uStrLenExt3) || (strcmp(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt3], szAWS_EXT3) != 0)) + { + if (strcmp(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt1], szAWS_EXT1) == 0) + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt1], szAWS_EXT3); // "file.aws" -> "file" + ".aws.yaml" + else if (strcmp(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt2], szAWS_EXT2) == 0) + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt2], szAWS_EXT3); // "file.yaml" -> "file" + ".aws.yaml" + else + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile], szAWS_EXT3); // "file" += ".aws.yaml" + } } + strcpy(m_szSSNewFilename, &szFilename[ofn.nFileOffset]); strcpy(m_szSSNewPathname, szFilename); szFilename[ofn.nFileOffset] = 0; @@ -319,41 +353,52 @@ bool CPropertySheetHelper::CheckChangesForRestart(HWND hWnd) return true; // OK } -#define CONFIG_CHANGED(var) \ - (m_ConfigOld.var != m_ConfigNew.var) +#define CONFIG_CHANGED_LOCAL(var) \ + (ConfigOld.var != ConfigNew.var) // Apply changes to Registry +void CPropertySheetHelper::ApplyNewConfig(const CConfigNeedingRestart& ConfigNew, const CConfigNeedingRestart& ConfigOld) +{ + if (CONFIG_CHANGED_LOCAL(m_Apple2Type)) + { + SaveComputerType(ConfigNew.m_Apple2Type); + } + + if (CONFIG_CHANGED_LOCAL(m_CpuType)) + { + SaveCpuType(ConfigNew.m_CpuType); + } + + if (CONFIG_CHANGED_LOCAL(m_Slot[4])) + SetSlot4(ConfigNew.m_Slot[4]); + + if (CONFIG_CHANGED_LOCAL(m_Slot[5])) + SetSlot5(ConfigNew.m_Slot[5]); + + if (CONFIG_CHANGED_LOCAL(m_bEnhanceDisk)) + REGSAVE(TEXT(REGVALUE_ENHANCE_DISK_SPEED), ConfigNew.m_bEnhanceDisk); + + if (CONFIG_CHANGED_LOCAL(m_bEnableHDD)) + { + REGSAVE(TEXT(REGVALUE_HDD_ENABLED), ConfigNew.m_bEnableHDD ? 1 : 0); + } + + if (CONFIG_CHANGED_LOCAL(m_bEnableTheFreezesF8Rom)) + { + REGSAVE(TEXT(REGVALUE_THE_FREEZES_F8_ROM), ConfigNew.m_bEnableTheFreezesF8Rom); + } +} + void CPropertySheetHelper::ApplyNewConfig(void) { - if (CONFIG_CHANGED(m_Apple2Type)) - { - SaveComputerType(m_ConfigNew.m_Apple2Type); - } - - if (CONFIG_CHANGED(m_Slot[4])) - SetSlot4(m_ConfigNew.m_Slot[4]); - - if (CONFIG_CHANGED(m_Slot[5])) - SetSlot5(m_ConfigNew.m_Slot[5]); - - if (CONFIG_CHANGED(m_bEnhanceDisk)) - REGSAVE(TEXT(REGVALUE_ENHANCE_DISK_SPEED), m_ConfigNew.m_bEnhanceDisk); - - if (CONFIG_CHANGED(m_bEnableHDD)) - { - REGSAVE(TEXT(REGVALUE_HDD_ENABLED), m_ConfigNew.m_bEnableHDD ? 1 : 0); - } - - if (CONFIG_CHANGED(m_bEnableTheFreezesF8Rom)) - { - REGSAVE(TEXT(REGVALUE_THE_FREEZES_F8_ROM), m_ConfigNew.m_bEnableTheFreezesF8Rom); - } + ApplyNewConfig(m_ConfigNew, m_ConfigOld); } void CPropertySheetHelper::SaveCurrentConfig(void) { // NB. clone-type is encoded in g_Apple2Type - m_ConfigOld.m_Apple2Type = g_Apple2Type; + m_ConfigOld.m_Apple2Type = GetApple2Type(); + m_ConfigOld.m_CpuType = GetMainCpu(); m_ConfigOld.m_Slot[4] = g_Slot4; m_ConfigOld.m_Slot[5] = g_Slot5; m_ConfigOld.m_bEnhanceDisk = enhancedisk; @@ -371,7 +416,8 @@ void CPropertySheetHelper::SaveCurrentConfig(void) void CPropertySheetHelper::RestoreCurrentConfig(void) { // NB. clone-type is encoded in g_Apple2Type - g_Apple2Type = m_ConfigOld.m_Apple2Type; + SetApple2Type(m_ConfigOld.m_Apple2Type); + SetMainCpu(m_ConfigOld.m_CpuType); g_Slot4 = m_ConfigOld.m_Slot[4]; g_Slot5 = m_ConfigOld.m_Slot[5]; enhancedisk = m_ConfigOld.m_bEnhanceDisk; @@ -411,6 +457,9 @@ bool CPropertySheetHelper::IsOkToRestart(HWND hWnd) return true; } +#define CONFIG_CHANGED(var) \ + (m_ConfigOld.var != m_ConfigNew.var) + bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd) { std::string strMsg("The emulator needs to restart as the hardware configuration has changed:\n"); @@ -421,6 +470,9 @@ bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd) if (CONFIG_CHANGED(m_Apple2Type)) strMsgMain += ". Emulated computer has changed\n"; + if (CONFIG_CHANGED(m_CpuType)) + strMsgMain += ". Emulated main CPU has changed\n"; + if (CONFIG_CHANGED(m_Slot[4])) strMsgMain += GetSlot(4); diff --git a/source/Configuration/PropertySheetHelper.h b/source/Configuration/PropertySheetHelper.h index 74896cdb..5fd83fd4 100644 --- a/source/Configuration/PropertySheetHelper.h +++ b/source/Configuration/PropertySheetHelper.h @@ -18,7 +18,6 @@ public: void SetSlot5(SS_CARDTYPE NewCardType); std::string BrowseToFile(HWND hWindow, TCHAR* pszTitle, TCHAR* REGVALUE,TCHAR* FILEMASKS); void SaveStateUpdate(); - void GetDiskBaseNameWithAWS(TCHAR* pszFilename); int SaveStateSelectImage(HWND hWindow, TCHAR* pszTitle, bool bSave); void PostMsgAfterClose(HWND hWnd, PAGETYPE page); @@ -37,17 +36,20 @@ public: CConfigNeedingRestart& GetConfigNew(void) { return m_ConfigNew; } bool IsConfigChanged(void) { return m_ConfigNew != m_ConfigOld; } void SetDoBenchmark(void) { m_bDoBenchmark = true; } + void ApplyNewConfig(const CConfigNeedingRestart& ConfigNew, const CConfigNeedingRestart& ConfigOld); private: bool IsOkToSaveLoadState(HWND hWnd, const bool bConfigChanged); bool IsOkToRestart(HWND hWnd); void SaveComputerType(eApple2Type NewApple2Type); + void SaveCpuType(eCpuType NewCpuType); bool HardwareConfigChanged(HWND hWnd); bool CheckChangesForRestart(HWND hWnd); void ApplyNewConfig(void); void RestoreCurrentConfig(void); std::string GetSlot(const UINT uSlot); std::string GetCardName(const SS_CARDTYPE CardType); + void GetDiskBaseNameWithAWS(TCHAR* pszFilename); PAGETYPE m_LastPage; UINT32 m_bmPages; diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 1441ad97..a985c577 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -1955,7 +1955,7 @@ Update_t CmdTraceFile (int nArgs) fclose( g_hTraceFile ); g_hTraceFile = NULL; - sprintf( sText, "Trace stopped." ); + _snprintf( sText, sizeof(sText), "Trace stopped." ); } else { @@ -1975,16 +1975,17 @@ Update_t CmdTraceFile (int nArgs) if (g_hTraceFile) { - sprintf( sText, "Trace started: %s", sFilePath ); + _snprintf( sText, sizeof(sText), "Trace started: %s", sFilePath ); g_bTraceHeader = true; } else { - sprintf( sText, "Trace ERROR: %s", sFilePath ); + _snprintf( sText, sizeof(sText), "Trace ERROR: %s", sFilePath ); } } - + + sText[sizeof(sText)-1] = 0; // _snprintf needs null if string was longer than buffer ConsoleBufferPush( sText ); ConsoleBufferToDisplay(); @@ -2313,7 +2314,7 @@ void ConfigSave_PrepareHeader ( const Parameters_e eCategory, const Commands_e e sprintf( sText, "%s %s = %s\n" , g_aTokens[ TOKEN_COMMENT_EOL ].sToken , g_aParameters[ PARAM_CATEGORY ].m_sName - , g_aParameters[ eCategory ] + , g_aParameters[ eCategory ].m_sName ); g_ConfigState.PushLine( sText ); @@ -4297,10 +4298,10 @@ Update_t CmdMemoryLoad (int nArgs) TCHAR sLoadSaveFilePath[ MAX_PATH ]; _tcscpy( sLoadSaveFilePath, g_sCurrentDir ); // TODO: g_sDebugDir - WORD nAddressStart; - WORD nAddress2 = 0; - WORD nAddressEnd = 0; - int nAddressLen = 0; + WORD nAddressStart = 0; + WORD nAddress2 = 0; + WORD nAddressEnd = 0; + int nAddressLen = 0; if( pFileType ) { @@ -4370,7 +4371,7 @@ Update_t CmdMemoryLoad (int nArgs) if (bBankSpecified) { - MemUpdatePaging(1); + MemUpdatePaging(TRUE); } else { @@ -5975,6 +5976,7 @@ Update_t CmdOutputPrintf (int nArgs) { case '\\': eThis = PS_ESCAPE; + break; case '%': eThis = PS_TYPE; break; @@ -7027,7 +7029,6 @@ Update_t CmdWindowViewCode (int nArgs) Update_t CmdWindowViewConsole (int nArgs) { return _CmdWindowViewFull( WINDOW_CONSOLE ); - return UPDATE_ALL; } //=========================================================================== @@ -7049,14 +7050,12 @@ Update_t CmdWindowViewOutput (int nArgs) Update_t CmdWindowViewSource (int nArgs) { return _CmdWindowViewFull( WINDOW_CONSOLE ); - return UPDATE_ALL; } //=========================================================================== Update_t CmdWindowViewSymbols (int nArgs) { return _CmdWindowViewFull( WINDOW_CONSOLE ); - return UPDATE_ALL; } //=========================================================================== @@ -7771,7 +7770,7 @@ void OutputTraceLine () (unsigned)regs.sp, (char*) sFlags , sDisassembly - , sTarget + //, sTarget // TODO: Show target? ); } } diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h index 8c1fdc79..add6cca5 100644 --- a/source/Debugger/Debug.h +++ b/source/Debugger/Debug.h @@ -1,6 +1,6 @@ #pragma once -#include "..\Structs.h" +#include "..\SaveState_Structs_v1.h" // For SS_CARD_MOCKINGBOARD #include "..\Common.h" #include "Debugger_Types.h" diff --git a/source/Debugger/Debugger_Assembler.cpp b/source/Debugger/Debugger_Assembler.cpp index 63a46f81..4c2730cd 100644 --- a/source/Debugger/Debugger_Assembler.cpp +++ b/source/Debugger/Debugger_Assembler.cpp @@ -565,7 +565,6 @@ bool _6502_GetStackReturnAddress ( WORD & nAddress_ ) if (nStack <= (_6502_STACK_END - 1)) { - nAddress_ = 0; nAddress_ = (unsigned)*(LPBYTE)(mem + nStack); nStack++; diff --git a/source/Debugger/Debugger_Commands.cpp b/source/Debugger/Debugger_Commands.cpp index 105561d2..970ec3d1 100644 --- a/source/Debugger/Debugger_Commands.cpp +++ b/source/Debugger/Debugger_Commands.cpp @@ -40,345 +40,345 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Command_t g_aCommands[] = { // Assembler -// {"!" , CmdAssemberMini , CMD_ASSEMBLER_MINI , "Mini assembler" } - {"A" , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" } +// {TEXT("!") , CmdAssemberMini , CMD_ASSEMBLER_MINI , "Mini assembler" }, + {TEXT("A") , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" }, // CPU (Main) - ,{"." , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" } // centered - ,{"=" , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" } -// ,{"g" , CmdGoNormalSpeed , CMD_GO_NORMAL , "Run @ normal speed [until PC == address]" } -// ,{"G" , CmdGoFullSpeed , CMD_GO_FULL , "Run @ full speed [until PC == address]" } - ,{"G" , CmdGo , CMD_GO , "Run @ full speed [until PC == address]" } - ,{"IN" , CmdIn , CMD_IN , "Input byte from IO $C0xx" } - ,{"KEY" , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" } - ,{"JSR" , CmdJSR , CMD_JSR , "Call sub-routine" } - ,{"NOP" , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" } - ,{"OUT" , CmdOut , CMD_OUT , "Output byte to IO $C0xx" } + {TEXT(".") , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" }, // centered + {TEXT("=") , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" }, +// {TEXT("g") , CmdGoNormalSpeed , CMD_GO_NORMAL , "Run @ normal speed [until PC == address]" }, +// {TEXT("G") , CmdGoFullSpeed , CMD_GO_FULL , "Run @ full speed [until PC == address]" }, + {TEXT("G") , CmdGo , CMD_GO , "Run @ full speed [until PC == address]" }, + {TEXT("IN") , CmdIn , CMD_IN , "Input byte from IO $C0xx" }, + {TEXT("KEY") , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" }, + {TEXT("JSR") , CmdJSR , CMD_JSR , "Call sub-routine" }, + {TEXT("NOP") , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" }, + {TEXT("OUT") , CmdOut , CMD_OUT , "Output byte to IO $C0xx" }, // CPU - Meta Info - ,{"PROFILE" , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" } - ,{"R" , CmdRegisterSet , CMD_REGISTER_SET , "Set register" } + {TEXT("PROFILE") , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" }, + {TEXT("R") , CmdRegisterSet , CMD_REGISTER_SET , "Set register" }, // CPU - Stack - ,{"POP" , CmdStackPop , CMD_STACK_POP } - ,{"PPOP" , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO } - ,{"PUSH" , CmdStackPop , CMD_STACK_PUSH } -// ,{"RTS" , CmdStackReturn , CMD_STACK_RETURN } - ,{"P" , CmdStepOver , CMD_STEP_OVER , "Step current instruction" } - ,{"RTS" , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" } + {TEXT("POP") , CmdStackPop , CMD_STACK_POP }, + {TEXT("PPOP") , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO }, + {TEXT("PUSH") , CmdStackPop , CMD_STACK_PUSH }, +// {TEXT("RTS") , CmdStackReturn , CMD_STACK_RETURN }, + {TEXT("P") , CmdStepOver , CMD_STEP_OVER , "Step current instruction" }, + {TEXT("RTS") , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" }, // CPU - Meta Info - ,{"T" , CmdTrace , CMD_TRACE , "Trace current instruction" } - ,{"TF" , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" } - ,{"TL" , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" } - ,{"U" , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" } -// ,{"WAIT" , CmdWait , CMD_WAIT , "Run until" + {TEXT("T") , CmdTrace , CMD_TRACE , "Trace current instruction" }, + {TEXT("TF") , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" }, + {TEXT("TL") , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" }, + {TEXT("U") , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" }, +// {TEXT("WAIT") , CmdWait , CMD_WAIT , "Run until // Bookmarks - ,{"BM" , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" } - ,{"BMA" , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" } - ,{"BMC" , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" } - ,{"BML" , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" } - ,{"BMG" , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" } -// ,{"BMLOAD" , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" } - ,{"BMSAVE" , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" } + {TEXT("BM") , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" }, + {TEXT("BMA") , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" }, + {TEXT("BMC") , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" }, + {TEXT("BML") , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" }, + {TEXT("BMG") , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" }, +// {TEXT("BMLOAD") , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" }, + {TEXT("BMSAVE") , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" }, // Breakpoints - ,{"BRK" , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" } - ,{"BRKOP" , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" } - ,{"BP" , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" } - ,{"BPA" , CmdBreakpointAddSmart , CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" } -// ,{"BPP" , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" } - ,{"BPR" , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" } // NOTE! Different from SoftICE !!!! - ,{"BPX" , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" } - ,{"BPIO" , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" } - ,{"BPM" , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" } // SoftICE + {TEXT("BRK") , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" }, + {TEXT("BRKOP") , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" }, + {TEXT("BP") , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" }, + {TEXT("BPA") , CmdBreakpointAddSmart, CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" }, +// {TEXT("BPP") , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" }, + {TEXT("BPR") , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" }, // NOTE! Different from SoftICE !!!! + {TEXT("BPX") , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" }, + {TEXT("BPIO") , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" }, + {TEXT("BPM") , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" }, // SoftICE - ,{"BPC" , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" } // SoftICE - ,{"BPD" , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" } // SoftICE - ,{"BPEDIT" , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" } // SoftICE - ,{"BPE" , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" } // SoftICE - ,{"BPL" , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" } // SoftICE -// ,{"BPLOAD" , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" } - ,{"BPSAVE" , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" } + {TEXT("BPC") , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" }, // SoftICE + {TEXT("BPD") , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" }, // SoftICE + {TEXT("BPEDIT") , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" }, // SoftICE + {TEXT("BPE") , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" }, // SoftICE + {TEXT("BPL") , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" }, // SoftICE +// {TEXT("BPLOAD") , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" }, + {TEXT("BPSAVE") , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" }, // Config - ,{"BENCHMARK" , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" } - ,{"BW" , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" } - ,{"COLOR" , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" } -// ,{"OPTION" , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" } - ,{"DISASM" , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." } - ,{"FONT" , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" } - ,{"HCOLOR" , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" } - ,{"LOAD" , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" } - ,{"MONO" , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" } - ,{"SAVE" , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" } - ,{"PWD" , CmdConfigGetDebugDir , CMD_CONFIG_GET_DEBUG_DIR , "Display current debugger directory for scripts & mem load/save." } - ,{"CD" , CmdConfigSetDebugDir , CMD_CONFIG_SET_DEBUG_DIR , "Update current debugger directory." } + {TEXT("BENCHMARK") , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" }, + {TEXT("BW") , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" }, + {TEXT("COLOR") , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" }, +// {TEXT("OPTION") , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" }, + {TEXT("DISASM") , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." }, + {TEXT("FONT") , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" }, + {TEXT("HCOLOR") , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" }, + {TEXT("LOAD") , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" }, + {TEXT("MONO") , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" }, + {TEXT("SAVE") , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" }, + {TEXT("PWD") , CmdConfigGetDebugDir , CMD_CONFIG_GET_DEBUG_DIR , "Displays the current debugger directory. Used for scripts & mem load/save." }, + {TEXT("CD") , CmdConfigSetDebugDir , CMD_CONFIG_SET_DEBUG_DIR , "Updates the current debugger directory." }, // Cursor - ,{"RET" , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the subroutine caller" } - ,{ "^" , NULL , CMD_CURSOR_LINE_UP } // \x2191 = Up Arrow (Unicode) - ,{"Shift ^" , NULL , CMD_CURSOR_LINE_UP_1 } - ,{ "v" , NULL , CMD_CURSOR_LINE_DOWN } // \x2193 = Dn Arrow (Unicode) - ,{"Shift v" , NULL , CMD_CURSOR_LINE_DOWN_1 } - ,{"PAGEUP" , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" } - ,{"PAGEUP256" , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" } // Shift - ,{"PAGEUP4K" , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" } // Ctrl - ,{"PAGEDN" , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" } - ,{"PAGEDOWN256" , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" } // Shift - ,{"PAGEDOWN4K" , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" } // Ctrl + {TEXT("RET") , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the sub-routine caller" }, + {TEXT( "^") , NULL , CMD_CURSOR_LINE_UP }, // \x2191 = Up Arrow (Unicode) + {TEXT("Shift ^") , NULL , CMD_CURSOR_LINE_UP_1 }, + {TEXT( "v") , NULL , CMD_CURSOR_LINE_DOWN }, // \x2193 = Dn Arrow (Unicode) + {TEXT("Shift v") , NULL , CMD_CURSOR_LINE_DOWN_1 }, + {TEXT("PAGEUP" ) , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" }, + {TEXT("PAGEUP256") , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" }, // Shift + {TEXT("PAGEUP4K" ) , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" }, // Ctrl + {TEXT("PAGEDN" ) , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" }, + {TEXT("PAGEDOWN256") , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" }, // Shift + {TEXT("PAGEDOWN4K" ) , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" }, // Ctrl // Disassembler Data - ,{"Z" , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" } - ,{"X" , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" } + {TEXT("Z") , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" }, + {TEXT("X") , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" }, // TODO: Conflicts with monitor command #L -> 000DL - ,{"B" , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" } + {TEXT("B") , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" }, // without symbol lookup - ,{"DB" , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1 , "Define byte(s)" } - ,{"DB2" , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2 , "Define byte array, display 2 bytes/line" } - ,{"DB4" , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4 , "Define byte array, display 4 bytes/line" } - ,{"DB8" , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8 , "Define byte array, display 8 bytes/line" } - ,{"DW" , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1 , "Define address array" } - ,{"DW2" , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2 , "Define address array, display 2 words/line" } - ,{"DW4" , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4 , "Define address array, display 4 words/line" } - ,{"ASC" , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define text string" } // 2.7.0.26 Changed: DS to ASC because DS is used as "Define Space" assembler directive -// .{"DF" , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT , "Define AppleSoft (packed) Float" } -// .{"DFX" , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2 , "Define AppleSoft (unpacked) Float" } + {TEXT("DB") , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1, "Define byte(s)" }, + {TEXT("DB2") , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2, "Define byte array, display 2 bytes/line" }, + {TEXT("DB4") , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4, "Define byte array, display 4 bytes/line" }, + {TEXT("DB8") , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8, "Define byte array, display 8 bytes/line" }, + {TEXT("DW") , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1, "Define address array" }, + {TEXT("DW2") , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2, "Define address array, display 2 words/line" }, + {TEXT("DW4") , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4, "Define address array, display 4 words/line" }, + {TEXT("ASC") , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define text string" }, // 2.7.0.26 Changed: DS to ASC because DS is used as "Define Space" assembler directive +// {TEXT("DF") , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT, "Define AppleSoft (packed) Float" }, +// {TEXT("DFX") , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2,"Define AppleSoft (unpacked) Float" }, // with symbol lookup -// .{"DA<>" , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" } -// .{"DA><" , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" } -// .{"DA<" , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" } -// .{"DB>" , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } - ,{"DA" , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" } +// {TEXT("DA<>") , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" }, +// {TEXT("DA><") , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" }, +// {TEXT("DA<") , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" }, +// {TEXT("DB>") , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } + {TEXT("DA") , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" }, // TODO: Rename config cmd: DISASM -// {"UA" , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE , "Analyze opcodes to determine if code or data" } +// {TEXT("UA") , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE, "Analyze opcodes to determine if code or data" }, // Disk - ,{"DISK" , CmdDisk , CMD_DISK , "Access Disk Drive Functions" } + {TEXT("DISK") , CmdDisk , CMD_DISK , "Access Disk Drive Functions" }, // Flags -// {"FC" , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" } // NVRBDIZC see AW_CPU.cpp AF_* +// {TEXT("FC") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* // TODO: Conflicts with monitor command #L -> 000CL - ,{"CL" , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" } // NVRBDIZC see AW_CPU.cpp AF_* + {TEXT("CL") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* - ,{"CLC" , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" } // 0 // Legacy - ,{"CLZ" , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" } // 1 - ,{"CLI" , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" } // 2 - ,{"CLD" , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" } // 3 - ,{"CLB" , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" } // 4 // Legacy - ,{"CLR" , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" } // 5 - ,{"CLV" , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" } // 6 - ,{"CLN" , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" } // 7 + {TEXT("CLC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy + {TEXT("CLZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 + {TEXT("CLI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 + {TEXT("CLD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 + {TEXT("CLB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("CLR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 + {TEXT("CLV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 + {TEXT("CLN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 -// ,{"FS" , CmdFlag , CMD_FLAG_SET , "Set specified Flag" } - ,{"SE" , CmdFlag , CMD_FLAG_SET , "Set specified Flag" } +// {TEXT("FS") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, + {TEXT("SE") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, - ,{"SEC" , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" } // 0 - ,{"SEZ" , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" } // 1 - ,{"SEI" , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" } // 2 - ,{"SED" , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" } // 3 - ,{"SEB" , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" } // 4 // Legacy - ,{"SER" , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" } // 5 - ,{"SEV" , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" } // 6 - ,{"SEN" , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" } // 7 + {TEXT("SEC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 + {TEXT("SEZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 + {TEXT("SEI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 + {TEXT("SED") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 + {TEXT("SEB") , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" }, // 4 // Legacy + {TEXT("SER") , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" }, // 5 + {TEXT("SEV") , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" }, // 6 + {TEXT("SEN") , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" }, // 7 // Help - ,{"?" , CmdHelpList , CMD_HELP_LIST , "List all available commands" } - ,{"HELP" , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" } - ,{"VERSION" , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" } - ,{"MOTD" , CmdMOTD , CMD_MOTD } // MOTD: Message Of The Day + {TEXT("?") , CmdHelpList , CMD_HELP_LIST , "List all available commands" }, + {TEXT("HELP") , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" }, + {TEXT("VERSION") , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" }, + {TEXT("MOTD") , CmdMOTD , CMD_MOTD }, // MOTD: Message Of The Day // Memory - ,{"MC" , CmdMemoryCompare , CMD_MEMORY_COMPARE } + {TEXT("MC") , CmdMemoryCompare , CMD_MEMORY_COMPARE }, - ,{"MD1" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" } - ,{"MD2" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" } + {TEXT("MD1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, + {TEXT("MD2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" }, - ,{"MA1" , CmdMemoryMiniDumpAscii , CMD_MEM_MINI_DUMP_ASCII_1 , "ASCII text in mini memory area 1" } - ,{"MA2" , CmdMemoryMiniDumpAscii , CMD_MEM_MINI_DUMP_ASCII_2 , "ASCII text in mini memory area 2" } - ,{"MT1" , CmdMemoryMiniDumpApple , CMD_MEM_MINI_DUMP_APPLE_1 , "Apple Text in mini memory area 1" } - ,{"MT2" , CmdMemoryMiniDumpApple , CMD_MEM_MINI_DUMP_APPLE_2 , "Apple Text in mini memory area 2" } -// {"ML1" , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1 , "Text (Ctrl) in mini memory dump area 1" } -// {"ML2" , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2 , "Text (Ctrl) in mini memory dump area 2" } -// {"MH1" , CmdMemoryMiniDumpHigh , CMD_MEM_MINI_DUMP_TXT_HI_1 , "Text (High) in mini memory dump area 1" } -// {"MH2" , CmdMemoryMiniDumpHigh , CMD_MEM_MINI_DUMP_TXT_HI_2 , "Text (High) in mini memory dump area 2" } + {TEXT("MA1") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_1, "ASCII text in mini memory area 1" }, + {TEXT("MA2") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_2, "ASCII text in mini memory area 2" }, + {TEXT("MT1") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_1, "Apple Text in mini memory area 1" }, + {TEXT("MT2") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_2, "Apple Text in mini memory area 2" }, +// {TEXT("ML1") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1, "Text (Ctrl) in mini memory dump area 1" }, +// {TEXT("ML2") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2, "Text (Ctrl) in mini memory dump area 2" }, +// {TEXT("MH1") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_1, "Text (High) in mini memory dump area 1" }, +// {TEXT("MH2") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_2, "Text (High) in mini memory dump area 2" }, - ,{"ME" , CmdMemoryEdit , CMD_MEMORY_EDIT , "Memory Editor - Not Implemented!" } // TODO: like Copy ][+ Sector Edit - ,{"MEB" , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" } - ,{"MEW" , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" } - ,{"BLOAD" , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" } - ,{"M" , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" } - ,{"BSAVE" , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" } - ,{"S" , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" } - ,{"@" ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" } -// ,{"SA" , CmdMemorySearchAscii , CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" } -// ,{"ST" , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" } - ,{"SH" , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" } - ,{"F" , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" } + {TEXT("ME") , CmdMemoryEdit , CMD_MEMORY_EDIT , "Memory Editor - Not Implemented!" }, // TODO: like Copy ][+ Sector Edit + {TEXT("MEB") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" }, + {TEXT("MEW") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" }, + {TEXT("BLOAD") , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" }, + {TEXT("M") , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" }, + {TEXT("BSAVE") , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" }, + {TEXT("S") , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" }, + {TEXT("@") ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" }, +// {TEXT("SA") , CmdMemorySearchAscii, CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" }, +// {TEXT("ST") , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" }, + {TEXT("SH") , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" }, + {TEXT("F") , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" }, - ,{"NTSC" , CmdNTSC , CMD_NTSC , "Save/Load the NTSC palette" } - ,{"TSAVE" , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" } + {TEXT("NTSC") , CmdNTSC , CMD_NTSC , "Save/Load the NTSC palette" }, + {TEXT("TSAVE") , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" }, // Output / Scripts - ,{"CALC" , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" } - ,{"ECHO" , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" } // or toggle command echoing" - ,{"PRINT" , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" } - ,{"PRINTF" , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" } - ,{"RUN" , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" } + {TEXT("CALC") , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" }, + {TEXT("ECHO") , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" }, // or toggle command echoing" + {TEXT("PRINT") , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" }, + {TEXT("PRINTF") , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" }, + {TEXT("RUN") , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" }, // Source Level Debugging - ,{"SOURCE" , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" } - ,{"SYNC" , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" } + {TEXT("SOURCE") , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" }, + {TEXT("SYNC") , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" }, // Symbols - ,{"SYM" , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" } + {TEXT("SYM") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" }, - ,{"SYMMAIN" , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMBASIC" , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMASM" , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMUSER" , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMUSER2" , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMSRC" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMSRC2" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMDOS33" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 , "DOS 3.3 symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMPRODOS" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS , "ProDOS symbol table lookup/menu" } // CLEAR,LOAD,SAVE + {"SYMMAIN" , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMBASIC" , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMASM" , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMUSER" , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMUSER2" , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMSRC" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMSRC2" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMDOS33" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 , "DOS 3.3 symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMPRODOS" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS , "ProDOS symbol table lookup/menu" }, // CLEAR,LOAD,SAVE -// ,{"SYMCLEAR" , CmdSymbolsClear , CMD_SYMBOLS_CLEAR } // can't use SC = SetCarry - ,{"SYMINFO" , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" } - ,{"SYMLIST" , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" } // 'symbolname', can't use param '*' +// {TEXT("SYMCLEAR") , CmdSymbolsClear , CMD_SYMBOLS_CLEAR }, // can't use SC = SetCarry + {TEXT("SYMINFO") , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" }, + {TEXT("SYMLIST") , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" }, // 'symbolname', can't use param '*' // Variables -// ,{"CLEAR" , CmdVarsClear , CMD_VARIABLES_CLEAR } -// ,{"VAR" , CmdVarsDefine , CMD_VARIABLES_DEFINE } -// ,{"INT8" , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8 } -// ,{"INT16" , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16 } -// ,{"VARS" , CmdVarsList , CMD_VARIABLES_LIST } -// ,{"VARSLOAD" , CmdVarsLoad , CMD_VARIABLES_LOAD } -// ,{"VARSSAVE" , CmdVarsSave , CMD_VARIABLES_SAVE } -// ,{"SET" , CmdVarsSet , CMD_VARIABLES_SET } +// {TEXT("CLEAR") , CmdVarsClear , CMD_VARIABLES_CLEAR }, +// {TEXT("VAR") , CmdVarsDefine , CMD_VARIABLES_DEFINE }, +// {TEXT("INT8") , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8}, +// {TEXT("INT16") , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16}, +// {TEXT("VARS") , CmdVarsList , CMD_VARIABLES_LIST }, +// {TEXT("VARSLOAD") , CmdVarsLoad , CMD_VARIABLES_LOAD }, +// {TEXT("VARSSAVE") , CmdVarsSave , CMD_VARIABLES_SAVE }, +// {TEXT("SET") , CmdVarsSet , CMD_VARIABLES_SET }, // View - ,{"TEXT" , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X , "View Text screen (current page)" } - ,{"TEXT1" , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 , "View Text screen Page 1" } - ,{"TEXT2" , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 , "View Text screen Page 2" } - ,{"TEXT80" , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X , "View 80-col Text screen (current page)" } - ,{"TEXT81" , CmdViewOutput_Text81 , CMD_VIEW_TEXT81 , "View 80-col Text screen Page 1" } - ,{"TEXT82" , CmdViewOutput_Text82 , CMD_VIEW_TEXT82 , "View 80-col Text screen Page 2" } - ,{"GR" , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" } - ,{"GR1" , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" } - ,{"GR2" , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" } - ,{"DGR" , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" } - ,{"DGR1" , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" } - ,{"DGR2" , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" } - ,{"HGR" , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" } - ,{"HGR1" , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" } - ,{"HGR2" , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" } - ,{"DHGR" , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" } - ,{"DHGR1" , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" } - ,{"DHGR2" , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" } + {TEXT("TEXT") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X, "View Text screen (current page)" }, + {TEXT("TEXT1") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41, "View Text screen Page 1" }, + {TEXT("TEXT2") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42, "View Text screen Page 2" }, + {TEXT("TEXT80") , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X, "View 80-col Text screen (current page)" }, + {TEXT("TEXT81") , CmdViewOutput_Text81 , CMD_VIEW_TEXT81, "View 80-col Text screen Page 1" }, + {TEXT("TEXT82") , CmdViewOutput_Text82 , CMD_VIEW_TEXT82, "View 80-col Text screen Page 2" }, + {TEXT("GR") , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" }, + {TEXT("GR1") , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" }, + {TEXT("GR2") , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" }, + {TEXT("DGR") , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" }, + {TEXT("DGR1") , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" }, + {TEXT("DGR2") , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" }, + {TEXT("HGR") , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" }, + {TEXT("HGR1") , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" }, + {TEXT("HGR2") , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" }, + {TEXT("DHGR") , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" }, + {TEXT("DHGR1") , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" }, + {TEXT("DHGR2") , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" }, // Watch - ,{"W" , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" } - ,{"WA" , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" } - ,{"WC" , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" } - ,{"WD" , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - listed not active" } - ,{"WE" , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" } - ,{"WL" , CmdWatchList , CMD_WATCH_LIST , "List all watches" } -// ,{"WLOAD" , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" } // Cant use as param to W - ,{"WSAVE" , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" } // due to symbol look-up + {TEXT("W") , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" }, + {TEXT("WA") , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" }, + {TEXT("WC") , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" }, + {TEXT("WD") , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - it is still in the list, just not active" }, + {TEXT("WE") , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" }, + {TEXT("WL") , CmdWatchList , CMD_WATCH_LIST , "List all watches" }, +// {TEXT("WLOAD") , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" }, // Cant use as param to W + {TEXT("WSAVE") , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" }, // due to symbol look-up // Window - ,{"WIN" , CmdWindow , CMD_WINDOW , "Show specified debugger window" } + {TEXT("WIN") , CmdWindow , CMD_WINDOW , "Show specified debugger window" }, // CODE 0, CODE 1, CODE 2 ... ??? - ,{"CODE" , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" } // Can't use WC = WatchClear - ,{"CODE1" , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" } - ,{"CODE2" , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" } - ,{"CONSOLE" , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" } - ,{"DATA" , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" } - ,{"DATA1" , CmdWindowShowData1 , CMD_WINDOW_DATA_1 , "Show data on top split window" } - ,{"DATA2" , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" } - ,{"SOURCE1" , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1 , "Show source on top split screen" } - ,{"SOURCE2" , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2 , "Show source on bottom split screen" } + {TEXT("CODE") , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" }, // Can't use WC = WatchClear + {TEXT("CODE1") , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" }, + {TEXT("CODE2") , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" }, + {TEXT("CONSOLE") , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" }, + {TEXT("DATA") , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" }, + {TEXT("DATA1") , CmdWindowShowData1 , CMD_WINDOW_DATA_1 , "Show data on top split window" }, + {TEXT("DATA2") , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" }, + {TEXT("SOURCE1") , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1, "Show source on top split screen" }, + {TEXT("SOURCE2") , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2, "Show source on bottom split screen" }, - ,{"\\" , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" } -// ,{"INFO" , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE } -// ,{"WINSOURCE" , CmdWindowShowSource , CMD_WINDOW_SOURCE } -// ,{"ZEROPAGE" , CmdWindowShowZeropage , CMD_WINDOW_ZEROPAGE } + {TEXT("\\") , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" }, +// {TEXT("INFO") , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE }, +// {TEXT("WINSOURCE") , CmdWindowShowSource , CMD_WINDOW_SOURCE }, +// {TEXT("ZEROPAGE") , CmdWindowShowZeropage, CMD_WINDOW_ZEROPAGE }, // Zero Page - ,{"ZP" , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" } - ,{"ZP0" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " } - ,{"ZP1" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" } - ,{"ZP2" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" } - ,{"ZP3" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" } - ,{"ZP4" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" } - ,{"ZP5" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " } - ,{"ZP6" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" } - ,{"ZP7" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" } - ,{"ZPA" , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer" } - ,{"ZPC" , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" } - ,{"ZPD" , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE, "Disable zero page pointer" } - ,{"ZPE" , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE , "(Re)Enable disabled zero page pointer" } - ,{"ZPL" , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" } -// ,{"ZPLOAD" , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" } // Cant use as param to ZP - ,{"ZPSAVE" , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" } // due to symbol look-up + {TEXT("ZP") , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" }, + {TEXT("ZP0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " }, + {TEXT("ZP1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" }, + {TEXT("ZP2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" }, + {TEXT("ZP3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" }, + {TEXT("ZP4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" }, + {TEXT("ZP5") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " }, + {TEXT("ZP6") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" }, + {TEXT("ZP7") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" }, + {TEXT("ZPA") , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer"}, + {TEXT("ZPC") , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" }, + {TEXT("ZPD") , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE,"Disable zero page pointer - it is still in the list, just not active" }, + {TEXT("ZPE") , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE, "(Re)Enable disabled zero page pointer" }, + {TEXT("ZPL") , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" }, +// {TEXT("ZPLOAD") , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" }, // Cant use as param to ZP + {TEXT("ZPSAVE") , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" }, // due to symbol look-up -// {"TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() -// {"WC"),CmdShowCodeWindow}, // Can't use since WatchClear -// {"WD"),CmdShowDataWindow}, // +// {TEXT("TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() +// {TEXT("WC"),CmdShowCodeWindow}, // Can't use since WatchClear +// {TEXT("WD"),CmdShowDataWindow}, // // Internal Consistency Check - ,{ DEBUGGER__COMMANDS_VERIFY_TXT__, NULL, NUM_COMMANDS } + { DEBUGGER__COMMANDS_VERIFY_TXT__, NULL, NUM_COMMANDS }, // Aliasies - Can be in any order - ,{"->" , NULL , CMD_CURSOR_JUMP_PC } - ,{"Ctrl ->" , NULL , CMD_CURSOR_SET_PC } - ,{"Shift ->" , NULL , CMD_CURSOR_JUMP_PC } // at top - ,{"INPUT" , CmdIn , CMD_IN } + {TEXT("->") , NULL , CMD_CURSOR_JUMP_PC }, + {TEXT("Ctrl ->" ) , NULL , CMD_CURSOR_SET_PC }, + {TEXT("Shift ->") , NULL , CMD_CURSOR_JUMP_PC }, // at top + {TEXT("INPUT") , CmdIn , CMD_IN }, // Data // Flags - Clear - ,{"RC" , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" } // 0 // Legacy - ,{"RZ" , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" } // 1 - ,{"RI" , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" } // 2 - ,{"RD" , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" } // 3 - ,{"RB" , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" } // 4 // Legacy - ,{"RR" , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" } // 5 - ,{"RV" , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" } // 6 - ,{"RN" , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" } // 7 + {TEXT("RC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy + {TEXT("RZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 + {TEXT("RI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 + {TEXT("RD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 + {TEXT("RB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("RR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 + {TEXT("RV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 + {TEXT("RN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 // Flags - Set - ,{"SC" , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" } // 0 - ,{"SZ" , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" } // 1 - ,{"SI" , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" } // 2 - ,{"SD" , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" } // 3 - ,{"SB" , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" } // 4 // Legacy - ,{"SR" , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" } // 5 - ,{"SV" , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" } // 6 - ,{"SN" , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" } // 7 + {TEXT("SC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 + {TEXT("SZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 + {TEXT("SI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 + {TEXT("SD") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 + {TEXT("SB") , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("SR") , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" }, // 5 + {TEXT("SV") , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" }, // 6 + {TEXT("SN") , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" }, // 7 // Memory - ,{"D" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" } // FIXME: Must also work in DATA screen - ,{"M1" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // alias - ,{"M2" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 } // alias + {TEXT("D") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, // FIXME: Must also work in DATA screen + {TEXT("M1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // alias + {TEXT("M2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 }, // alias - ,{"ME8" , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE } // changed from EB -- bugfix: EB:## ## - ,{"ME16" , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD } - ,{"MM" , CmdMemoryMove , CMD_MEMORY_MOVE } - ,{"MS" , CmdMemorySearch , CMD_MEMORY_SEARCH } // CmdMemorySearch - ,{"P0" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 } - ,{"P1" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 } - ,{"P2" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 } - ,{"P3" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 } - ,{"P4" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 } - ,{"REGISTER" , CmdRegisterSet , CMD_REGISTER_SET } -// ,{"RET" , CmdStackReturn , CMD_STACK_RETURN } - ,{"TRACE" , CmdTrace , CMD_TRACE } + {TEXT("ME8") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE }, // changed from EB -- bugfix: EB:## ## + {TEXT("ME16") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD }, + {TEXT("MM") , CmdMemoryMove , CMD_MEMORY_MOVE }, + {TEXT("MS") , CmdMemorySearch , CMD_MEMORY_SEARCH }, // CmdMemorySearch + {TEXT("P0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 }, + {TEXT("P1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 }, + {TEXT("P2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 }, + {TEXT("P3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 }, + {TEXT("P4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 }, + {TEXT("REGISTER") , CmdRegisterSet , CMD_REGISTER_SET }, +// {TEXT("RET") , CmdStackReturn , CMD_STACK_RETURN }, + {TEXT("TRACE") , CmdTrace , CMD_TRACE }, -// ,{"SYMBOLS" , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " } -// ,{"SYMBOLS1" , CmdSymbolsInfo , CMD_SYMBOLS_1 } -// ,{"SYMBOLS2" , CmdSymbolsInfo , CMD_SYMBOLS_2 } -// ,{"SYM0" , CmdSymbolsInfo , CMD_SYMBOLS_ROM } -// ,{"SYM1" , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT } -// ,{"SYM2" , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY } -// ,{"SYM3" , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 } -// ,{"SYM4" , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 } -// ,{"SYM5" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 } -// ,{"SYM6" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 } - ,{"SYMDOS" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 } - ,{"SYMPRO" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS } +// {TEXT("SYMBOLS") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " }, +// {TEXT("SYMBOLS1") , CmdSymbolsInfo , CMD_SYMBOLS_1 }, +// {TEXT("SYMBOLS2") , CmdSymbolsInfo , CMD_SYMBOLS_2 }, +// {"SYM0" , CmdSymbolsInfo , CMD_SYMBOLS_ROM }, +// {"SYM1" , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT }, +// {"SYM2" , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY }, +// {"SYM3" , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 }, +// {"SYM4" , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 }, +// {"SYM5" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 }, +// {"SYM6" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 }, + {"SYMDOS" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 }, + {"SYMPRO" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS }, - ,{"TEXT40" , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X } - ,{"TEXT41" , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 } - ,{"TEXT42" , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 } + {TEXT("TEXT40") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X }, + {TEXT("TEXT41") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 }, + {TEXT("TEXT42") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 }, -// ,{"WATCH" , CmdWatchAdd , CMD_WATCH_ADD } - ,{"WINDOW" , CmdWindow , CMD_WINDOW } -// ,{"W?" , CmdWatchAdd , CMD_WATCH_ADD } - ,{"ZAP" , CmdNOP , CMD_NOP } +// {TEXT("WATCH") , CmdWatchAdd , CMD_WATCH_ADD }, + {TEXT("WINDOW") , CmdWindow , CMD_WINDOW }, +// {TEXT("W?") , CmdWatchAdd , CMD_WATCH_ADD }, + {TEXT("ZAP") , CmdNOP , CMD_NOP }, // DEPRECATED -- Probably should be removed in a future version - ,{"BENCH" , CmdBenchmarkStart , CMD_BENCHMARK } // already hae BENCHMARK - ,{"EXITBENCH" , NULL , CMD_BENCHMARK } // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop - ,{"MDB" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // MemoryDumpByte // Did anyone actually use this?? -// ,{"MEMORY" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // MemoryDumpByte // Did anyone actually use this?? + {TEXT("BENCH") , CmdBenchmarkStart , CMD_BENCHMARK }, + {TEXT("EXITBENCH") , NULL , CMD_BENCHMARK }, // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop + {TEXT("MDB") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? +// {TEXT("MEMORY") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? }; const int NUM_COMMANDS_WITH_ALIASES = sizeof(g_aCommands) / sizeof (Command_t); // Determined at compile-time ;-) @@ -391,114 +391,113 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Command_t g_aParameters[] = { // Breakpoint - {"<=" , NULL, PARAM_BP_LESS_EQUAL } - ,{"<" , NULL, PARAM_BP_LESS_THAN } - ,{"=" , NULL, PARAM_BP_EQUAL } - ,{"!=" , NULL, PARAM_BP_NOT_EQUAL } - ,{"!" , NULL, PARAM_BP_NOT_EQUAL_1 } - ,{">" , NULL, PARAM_BP_GREATER_THAN } - ,{">=" , NULL, PARAM_BP_GREATER_EQUAL } - ,{"R" , NULL, PARAM_BP_READ } - ,{"?" , NULL, PARAM_BP_READ } - ,{"W" , NULL, PARAM_BP_WRITE } - ,{"@" , NULL, PARAM_BP_WRITE } - ,{"*" , NULL, PARAM_BP_READ_WRITE } + {TEXT("<=") , NULL, PARAM_BP_LESS_EQUAL }, + {TEXT("<" ) , NULL, PARAM_BP_LESS_THAN }, + {TEXT("=" ) , NULL, PARAM_BP_EQUAL }, + {TEXT("!=") , NULL, PARAM_BP_NOT_EQUAL }, + {TEXT("!" ) , NULL, PARAM_BP_NOT_EQUAL_1 }, + {TEXT(">" ) , NULL, PARAM_BP_GREATER_THAN }, + {TEXT(">=") , NULL, PARAM_BP_GREATER_EQUAL }, + {TEXT("R") , NULL, PARAM_BP_READ }, + {TEXT("?") , NULL, PARAM_BP_READ }, + {TEXT("W") , NULL, PARAM_BP_WRITE }, + {TEXT("@") , NULL, PARAM_BP_WRITE }, + {TEXT("*") , NULL, PARAM_BP_READ_WRITE }, // Regs (for PUSH / POP) - ,{"A" , NULL, PARAM_REG_A } - ,{"X" , NULL, PARAM_REG_X } - ,{"Y" , NULL, PARAM_REG_Y } - ,{"PC" , NULL, PARAM_REG_PC } - ,{"S" , NULL, PARAM_REG_SP } -// ,{"G" , NULL, PARAM_REG_PC } + {TEXT("A") , NULL, PARAM_REG_A }, + {TEXT("X") , NULL, PARAM_REG_X }, + {TEXT("Y") , NULL, PARAM_REG_Y }, + {TEXT("PC") , NULL, PARAM_REG_PC }, + {TEXT("S") , NULL, PARAM_REG_SP }, // Flags - ,{"P" , NULL, PARAM_FLAGS } - ,{"C" , NULL, PARAM_FLAG_C } // ---- ---1 Carry - ,{"Z" , NULL, PARAM_FLAG_Z } // ---- --1- Zero - ,{"I" , NULL, PARAM_FLAG_I } // ---- -1-- Interrupt - ,{"D" , NULL, PARAM_FLAG_D } // ---- 1--- Decimal - ,{"B" , NULL, PARAM_FLAG_B } // ---1 ---- Break - ,{"R" , NULL, PARAM_FLAG_R } // --1- ---- Reserved - ,{"V" , NULL, PARAM_FLAG_V } // -1-- ---- Overflow - ,{"N" , NULL, PARAM_FLAG_N } // 1--- ---- Sign + {TEXT("P") , NULL, PARAM_FLAGS }, + {TEXT("C") , NULL, PARAM_FLAG_C }, // ---- ---1 Carry + {TEXT("Z") , NULL, PARAM_FLAG_Z }, // ---- --1- Zero + {TEXT("I") , NULL, PARAM_FLAG_I }, // ---- -1-- Interrupt + {TEXT("D") , NULL, PARAM_FLAG_D }, // ---- 1--- Decimal + {TEXT("B") , NULL, PARAM_FLAG_B }, // ---1 ---- Break + {TEXT("R") , NULL, PARAM_FLAG_R }, // --1- ---- Reserved + {TEXT("V") , NULL, PARAM_FLAG_V }, // -1-- ---- Overflow + {TEXT("N") , NULL, PARAM_FLAG_N }, // 1--- ---- Sign // Disasm - ,{"BRANCH" , NULL, PARAM_CONFIG_BRANCH } - ,{"COLON" , NULL, PARAM_CONFIG_COLON } - ,{"OPCODE" , NULL, PARAM_CONFIG_OPCODE } - ,{"POINTER" , NULL, PARAM_CONFIG_POINTER } - ,{"SPACES" , NULL, PARAM_CONFIG_SPACES } - ,{"TARGET" , NULL, PARAM_CONFIG_TARGET } + {TEXT("BRANCH") , NULL, PARAM_CONFIG_BRANCH }, + {TEXT("COLON") , NULL, PARAM_CONFIG_COLON }, + {TEXT("OPCODE") , NULL, PARAM_CONFIG_OPCODE }, + {TEXT("POINTER") , NULL, PARAM_CONFIG_POINTER }, + {TEXT("SPACES") , NULL, PARAM_CONFIG_SPACES }, + {TEXT("TARGET") , NULL, PARAM_CONFIG_TARGET }, // Disk - ,{"EJECT" , NULL, PARAM_DISK_EJECT } - ,{"INFO" , NULL, PARAM_DISK_INFO } - ,{"PROTECT" , NULL, PARAM_DISK_PROTECT } - ,{"READ" , NULL, PARAM_DISK_READ } + {TEXT("EJECT") , NULL, PARAM_DISK_EJECT }, + {TEXT("INFO") , NULL, PARAM_DISK_INFO }, + {TEXT("PROTECT") , NULL, PARAM_DISK_PROTECT }, + {TEXT("READ") , NULL, PARAM_DISK_READ }, // Font (Config) - ,{"MODE" , NULL, PARAM_FONT_MODE } // also INFO, CONSOLE, DISASM (from Window) + {TEXT("MODE") , NULL, PARAM_FONT_MODE }, // also INFO, CONSOLE, DISASM (from Window) // General - ,{"FIND" , NULL, PARAM_FIND } - ,{"BRANCH" , NULL, PARAM_BRANCH } - ,{"CATEGORY" , NULL, PARAM_CATEGORY } - ,{"CLEAR" , NULL, PARAM_CLEAR } - ,{"LOAD" , NULL, PARAM_LOAD } - ,{"LIST" , NULL, PARAM_LIST } - ,{"OFF" , NULL, PARAM_OFF } - ,{"ON" , NULL, PARAM_ON } - ,{"RESET" , NULL, PARAM_RESET } - ,{"SAVE" , NULL, PARAM_SAVE } - ,{"START" , NULL, PARAM_START } // benchmark - ,{"STOP" , NULL, PARAM_STOP } // benchmark + {TEXT("FIND") , NULL, PARAM_FIND }, + {TEXT("BRANCH") , NULL, PARAM_BRANCH }, + {"CATEGORY" , NULL, PARAM_CATEGORY }, + {TEXT("CLEAR") , NULL, PARAM_CLEAR }, + {TEXT("LOAD") , NULL, PARAM_LOAD }, + {TEXT("LIST") , NULL, PARAM_LIST }, + {TEXT("OFF") , NULL, PARAM_OFF }, + {TEXT("ON") , NULL, PARAM_ON }, + {TEXT("RESET") , NULL, PARAM_RESET }, + {TEXT("SAVE") , NULL, PARAM_SAVE }, + {TEXT("START") , NULL, PARAM_START }, // benchmark + {TEXT("STOP") , NULL, PARAM_STOP }, // benchmark // Help Categories - ,{"*" , NULL, PARAM_WILDSTAR } - ,{"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS } - ,{"BREAKPOINTS", NULL, PARAM_CAT_BREAKPOINTS } - ,{"CONFIG" , NULL, PARAM_CAT_CONFIG } - ,{"CPU" , NULL, PARAM_CAT_CPU } -// ,{"EXPRESSION" , - ,{"FLAGS" , NULL, PARAM_CAT_FLAGS } - ,{"HELP" , NULL, PARAM_CAT_HELP } - ,{"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD } - ,{"MEMORY" , NULL, PARAM_CAT_MEMORY } // alias // SOURCE [SYMBOLS] [MEMORY] filename - ,{"OUTPUT" , NULL, PARAM_CAT_OUTPUT } - ,{"OPERATORS" , NULL, PARAM_CAT_OPERATORS } - ,{"RANGE" , NULL, PARAM_CAT_RANGE } -// ,{"REGISTERS" NULL, PARAM_CAT_REGISTERS } - ,{"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS } - ,{"VIEW" , NULL, PARAM_CAT_VIEW } - ,{"WATCHES" , NULL, PARAM_CAT_WATCHES } - ,{"WINDOW" , NULL, PARAM_CAT_WINDOW } - ,{"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE } + {"*" , NULL, PARAM_WILDSTAR }, + {"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS }, + {"BREAKPOINTS" , NULL, PARAM_CAT_BREAKPOINTS }, + {"CONFIG" , NULL, PARAM_CAT_CONFIG }, + {"CPU" , NULL, PARAM_CAT_CPU }, +// {TEXT("EXPRESSION") , + {"FLAGS" , NULL, PARAM_CAT_FLAGS }, + {"HELP" , NULL, PARAM_CAT_HELP }, + {"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD }, + {"MEMORY" , NULL, PARAM_CAT_MEMORY }, // alias // SOURCE [SYMBOLS] [MEMORY] filename + {"OUTPUT" , NULL, PARAM_CAT_OUTPUT }, + {"OPERATORS" , NULL, PARAM_CAT_OPERATORS }, + {"RANGE" , NULL, PARAM_CAT_RANGE }, +// {TEXT("REGISTERS") , NULL, PARAM_CAT_REGISTERS }, + {"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS }, + {"VIEW" , NULL, PARAM_CAT_VIEW }, + {"WATCHES" , NULL, PARAM_CAT_WATCHES }, + {"WINDOW" , NULL, PARAM_CAT_WINDOW }, + {"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE }, // Memory - ,{"?" , NULL, PARAM_MEM_SEARCH_WILD } -// ,{"*" , NULL, PARAM_MEM_SEARCH_BYTE } + {TEXT("?") , NULL, PARAM_MEM_SEARCH_WILD }, +// {TEXT("*") , NULL, PARAM_MEM_SEARCH_BYTE }, // Source level debugging - ,{"MEM" , NULL, PARAM_SRC_MEMORY } - ,{"MEMORY" , NULL, PARAM_SRC_MEMORY } - ,{"SYM" , NULL, PARAM_SRC_SYMBOLS } - ,{"SYMBOLS" , NULL, PARAM_SRC_SYMBOLS } - ,{"MERLIN" , NULL, PARAM_SRC_MERLIN } - ,{"ORCA" , NULL, PARAM_SRC_ORCA } + {TEXT("MEM") , NULL, PARAM_SRC_MEMORY }, + {TEXT("MEMORY") , NULL, PARAM_SRC_MEMORY }, + {TEXT("SYM") , NULL, PARAM_SRC_SYMBOLS }, + {TEXT("SYMBOLS") , NULL, PARAM_SRC_SYMBOLS }, + {TEXT("MERLIN") , NULL, PARAM_SRC_MERLIN }, + {TEXT("ORCA") , NULL, PARAM_SRC_ORCA }, // View -// ,{"VIEW") , NULL, PARAM_SRC_??? }, +// {TEXT("VIEW") , NULL, PARAM_SRC_??? }, // Window Win Cmd WinEffects CmdEffects - ,{"CODE" , NULL, PARAM_CODE } // x x code win only switch to code window -// ,{"CODE1" , NULL, PARAM_CODE_1 } // - x code/data win - ,{"CODE2" , NULL, PARAM_CODE_2 } // - x code/data win - ,{"CONSOLE" , NULL, PARAM_CONSOLE } // x - switch to console window - ,{"DATA" , NULL, PARAM_DATA } // x x data win only switch to data window -// ,{"DATA1" , NULL, PARAM_DATA_1 } // - x code/data win - ,{"DATA2" , NULL, PARAM_DATA_2 } // - x code/data win - ,{"DISASM" , NULL, PARAM_DISASM } // - ,{"INFO" , NULL, PARAM_INFO } // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP - ,{"SOURCE" , NULL, PARAM_SOURCE } // x x switch to source window - ,{"SRC" , NULL, PARAM_SOURCE } // alias -// ,{"SOURCE_1" , NULL, PARAM_SOURCE_1 } // - x code/data - ,{"SOURCE2 " , NULL, PARAM_SOURCE_2 } // - x - ,{"SYMBOLS" , NULL, PARAM_SYMBOLS } // x x code/data win switch to symbols window - ,{"SYM" , NULL, PARAM_SYMBOLS } // alias x SOURCE [SYM] [MEM] filename -// ,{"SYMBOL1" , NULL, PARAM_SYMBOL_1 } // - x code/data win - ,{"SYMBOL2" , NULL, PARAM_SYMBOL_2 } // - x code/data win + {TEXT("CODE") , NULL, PARAM_CODE }, // x x code win only switch to code window +// {TEXT("CODE1") , NULL, PARAM_CODE_1 }, // - x code/data win + {TEXT("CODE2") , NULL, PARAM_CODE_2 }, // - x code/data win + {TEXT("CONSOLE") , NULL, PARAM_CONSOLE }, // x - switch to console window + {TEXT("DATA") , NULL, PARAM_DATA }, // x x data win only switch to data window +// {TEXT("DATA1") , NULL, PARAM_DATA_1 }, // - x code/data win + {TEXT("DATA2") , NULL, PARAM_DATA_2 }, // - x code/data win + {TEXT("DISASM") , NULL, PARAM_DISASM }, // + {TEXT("INFO") , NULL, PARAM_INFO }, // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP + {TEXT("SOURCE") , NULL, PARAM_SOURCE }, // x x switch to source window + {TEXT("SRC") , NULL, PARAM_SOURCE }, // alias +// {TEXT("SOURCE_1") , NULL, PARAM_SOURCE_1 }, // - x code/data + {TEXT("SOURCE2 ") , NULL, PARAM_SOURCE_2 }, // - x + {TEXT("SYMBOLS") , NULL, PARAM_SYMBOLS }, // x x code/data win switch to symbols window + {TEXT("SYM") , NULL, PARAM_SYMBOLS }, // alias x SOURCE [SYM] [MEM] filename +// {TEXT("SYMBOL1") , NULL, PARAM_SYMBOL_1 }, // - x code/data win + {TEXT("SYMBOL2") , NULL, PARAM_SYMBOL_2 }, // - x code/data win // Internal Consistency Check - ,{DEBUGGER__PARAMS_VERIFY_TXT__,NULL,NUM_PARAMS} + { DEBUGGER__PARAMS_VERIFY_TXT__, NULL, NUM_PARAMS }, }; //=========================================================================== @@ -512,7 +511,7 @@ void VerifyDebuggerCommandTable() if ( g_aCommands[ iCmd ].iCommand != iCmd) { sprintf( sText, "*** ERROR *** Enumerated Commands mis-matched at #%d!", iCmd ); - MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); + MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); PostQuitMessage( 1 ); } } @@ -521,14 +520,14 @@ void VerifyDebuggerCommandTable() if (strcmp( g_aCommands[ NUM_COMMANDS ].m_sName, DEBUGGER__COMMANDS_VERIFY_TXT__)) { sprintf( sText, "*** ERROR *** Total Commands mis-matched!" ); - MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); + MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); PostQuitMessage( 1 ); } if (strcmp( g_aParameters[ NUM_PARAMS ].m_sName, DEBUGGER__PARAMS_VERIFY_TXT__)) { sprintf( sText, "*** ERROR *** Total Parameters mis-matched!" ); - MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); + MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); PostQuitMessage( 2 ); } } diff --git a/source/Debugger/Debugger_Console.cpp b/source/Debugger/Debugger_Console.cpp index 4b907f72..901e9248 100644 --- a/source/Debugger/Debugger_Console.cpp +++ b/source/Debugger/Debugger_Console.cpp @@ -279,8 +279,9 @@ bool ConsoleBufferPush ( const char * pText ) const char *pSrc = pText; conchar_t *pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ]; - while ((x < CONSOLE_WIDTH) && (c = *pSrc)) + while ((x < CONSOLE_WIDTH) && *pSrc) { + c = *pSrc; if ((c == '\n') || (x == (CONSOLE_WIDTH - 1))) { *pDst = 0; diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 6e4c98dd..9b854941 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -1223,7 +1223,7 @@ void DrawBreakpoints ( int line ) //=========================================================================== int GetConsoleLineHeightPixels() { - int nHeight = nHeight = g_aFontConfig[ FONT_CONSOLE ]._nFontHeight; // _nLineHeight; // _nFontHeight; + int nHeight = g_aFontConfig[ FONT_CONSOLE ]._nFontHeight; // _nLineHeight; // _nFontHeight; /* if (g_iFontSpacing == FONT_SPACING_CLASSIC) { @@ -2434,10 +2434,10 @@ void DrawMemory ( int line, int iMemDump ) DEVICE_e eDevice = pMD->eDevice; MemoryView_e iView = pMD->eView; - SS_CARD_MOCKINGBOARD SS_MB; + SS_CARD_MOCKINGBOARD_v1 SS_MB; if ((eDevice == DEV_SY6522) || (eDevice == DEV_AY8910)) - MB_GetSnapshot(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5 + MB_GetSnapshot_v1(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5 int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; diff --git a/source/Debugger/Debugger_Help.cpp b/source/Debugger/Debugger_Help.cpp index b92223ba..84ed29ea 100644 --- a/source/Debugger/Debugger_Help.cpp +++ b/source/Debugger/Debugger_Help.cpp @@ -126,7 +126,7 @@ Update_t Help_Arg_1( int iCommandHelp ) { _Arg_1( iCommandHelp ); - wsprintf( g_aArgs[ 1 ].sArg, g_aCommands[ iCommandHelp ].m_sName ); // .3 Fixed: Help_Arg_1() now copies command name into arg.name + wsprintf( g_aArgs[ 1 ].sArg, "%s", g_aCommands[ iCommandHelp ].m_sName ); // .3 Fixed: Help_Arg_1() now copies command name into arg.name return CmdHelpSpecific( 1 ); } @@ -669,49 +669,49 @@ Update_t CmdHelpSpecific (int nArgs) // HACK: Major kludge to display category!!! if (iCmd <= CMD_UNASSEMBLE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_CPU ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_CPU ].m_sName ); else if (iCmd <= CMD_BOOKMARK_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_BOOKMARKS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_BOOKMARKS ].m_sName ); else if (iCmd <= CMD_BREAKPOINT_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_BREAKPOINTS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_BREAKPOINTS ].m_sName ); else if (iCmd <= CMD_CONFIG_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_CONFIG ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_CONFIG ].m_sName ); else if (iCmd <= CMD_CURSOR_PAGE_DOWN_4K) wsprintf( sCategory, "Scrolling" ); else if (iCmd <= CMD_FLAG_SET_N) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_FLAGS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_FLAGS ].m_sName ); else if (iCmd <= CMD_MOTD) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_HELP ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_HELP ].m_sName ); else if (iCmd <= CMD_MEMORY_FILL) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_MEMORY ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_MEMORY ].m_sName ); else if (iCmd <= CMD_OUTPUT_RUN) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_OUTPUT ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_OUTPUT ].m_sName ); else if (iCmd <= CMD_SYNC) wsprintf( sCategory, "Source" ); else if (iCmd <= CMD_SYMBOLS_LIST) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_SYMBOLS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_SYMBOLS ].m_sName ); else if (iCmd <= CMD_VIEW_DHGR2) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_VIEW ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_VIEW ].m_sName ); else if (iCmd <= CMD_WATCH_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_WATCHES ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_WATCHES ].m_sName ); else if (iCmd <= CMD_WINDOW_OUTPUT) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_WINDOW ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_WINDOW ].m_sName ); else if (iCmd <= CMD_ZEROPAGE_POINTER_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_ZEROPAGE ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_ZEROPAGE ].m_sName ); else wsprintf( sCategory, "Unknown!" ); diff --git a/source/Disk.cpp b/source/Disk.cpp index 211ca632..a239e1c8 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth -Copyright (C) 2006-2014, Tom Charlesworth, Michael Pohoreski +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski, Nick Westgate AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,21 +24,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: Disk * * Author: Various + * + * In comments, UTA2E is an abbreviation for a reference to "Understanding the Apple //e" by James Sather */ #include "StdAfx.h" +#include "SaveState_Structs_v1.h" + #include "AppleWin.h" #include "Disk.h" #include "DiskImage.h" #include "Frame.h" +#include "Log.h" #include "Memory.h" #include "Registry.h" #include "Video.h" +#include "YamlHelper.h" #include "..\resource\resource.h" #define LOG_DISK_ENABLED 0 +#define LOG_DISK_TRACKS 1 +#define LOG_DISK_MOTOR 0 +#define LOG_DISK_PHASES 0 +#define LOG_DISK_NIBBLES 0 // __VA_ARGS__ not supported on MSVC++ .NET 7.x #if (LOG_DISK_ENABLED) @@ -61,21 +71,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Private ________________________________________________________________________________________ - const int MAX_DISK_IMAGE_NAME = 15; - const int MAX_DISK_FULL_NAME = 127; - struct Disk_t { TCHAR imagename[ MAX_DISK_IMAGE_NAME + 1 ]; // (ie. no extension) TCHAR fullname [ MAX_DISK_FULL_NAME + 1 ]; // or : This is persisted to the snapshot file - std::string strDiskPathFilename; - std::string strFilenameInZip; // 0x00 or + std::string strFilenameInZip; // "" or HIMAGE imagehandle; // Init'd by DiskInsert() -> ImageOpen() + bool bWriteProtected; + // int track; LPBYTE trackimage; int phase; int byte; - bool bWriteProtected; BOOL trackimagedata; BOOL trackimagedirty; DWORD spinning; @@ -86,14 +93,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA { memcpy(imagename, other.imagename, sizeof(imagename)); memcpy(fullname , other.fullname, sizeof(fullname)); - strDiskPathFilename = other.strDiskPathFilename; strFilenameInZip = other.strFilenameInZip; imagehandle = other.imagehandle; + bWriteProtected = other.bWriteProtected; track = other.track; trackimage = other.trackimage; phase = other.phase; byte = other.byte; - bWriteProtected = other.bWriteProtected; trackimagedata = other.trackimagedata; trackimagedirty = other.trackimagedirty; spinning = other.spinning; @@ -108,9 +114,11 @@ static BOOL diskaccessed = 0; static Disk_t g_aFloppyDisk[NUM_DRIVES]; static BYTE floppylatch = 0; static BOOL floppymotoron = 0; +static BOOL floppyloadmode = 0; // for efficiency this is not used; it's extremely unlikely to affect emulation (nickw) static BOOL floppywritemode = 0; -static WORD phases; // state bits for stepper magnet phases 0 - 3 +static WORD phases = 0; // state bits for stepper magnet phases 0 - 3 static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry +static UINT g_uSlot = 0; static void CheckSpinning(); static Disk_Status_e GetDriveLightStatus( const int iDrive ); @@ -118,6 +126,7 @@ static bool IsDriveValid( const int iDrive ); static void ReadTrack (int drive); static void RemoveDisk (int drive); static void WriteTrack (int drive); +static LPCTSTR DiskGetFullPathName(const int iDrive); //=========================================================================== @@ -127,14 +136,9 @@ int DiskGetCurrentPhase(void) { return g_aFloppyDisk[currdrive].phase; } int DiskGetCurrentOffset(void) { return g_aFloppyDisk[currdrive].byte; } int DiskGetTrack( int drive ) { return g_aFloppyDisk[ drive ].track; } -const std::string& DiskGetDiskPathFilename(const int iDrive) +const char* DiskGetDiskPathFilename(const int iDrive) { - return g_aFloppyDisk[iDrive].strDiskPathFilename; -} - -static void DiskSetDiskPathFilename(const int iDrive, const std::string strPathName) -{ - g_aFloppyDisk[iDrive].strDiskPathFilename = strPathName; + return g_aFloppyDisk[iDrive].fullname; } char* DiskGetCurrentState(void) @@ -152,19 +156,27 @@ char* DiskGetCurrentState(void) else if (floppywritemode) { if (g_aFloppyDisk[currdrive].bWriteProtected) - return "Writing"; - else return "Writing (write protected)"; + else + return "Writing"; } else { - return "Reading"; + /*if (floppyloadmode) + { + if (g_aFloppyDisk[currdrive].bWriteProtected) + return "Reading write protect state (write protected)"; + else + return "Reading write protect state (not write protected)"; + } + else*/ + return "Reading"; } } //=========================================================================== - void Disk_LoadLastDiskImage(const int iDrive) +void Disk_LoadLastDiskImage(const int iDrive) { _ASSERT(iDrive == DRIVE_1 || iDrive == DRIVE_2); @@ -175,22 +187,15 @@ char* DiskGetCurrentState(void) ? REGVALUE_PREF_LAST_DISK_1 : REGVALUE_PREF_LAST_DISK_2; - if (RegLoadString(TEXT(REG_PREFS),pRegKey,1,sFilePath,MAX_PATH)) + if (RegLoadString(TEXT(REG_PREFS), pRegKey, 1, sFilePath, MAX_PATH)) { sFilePath[ MAX_PATH ] = 0; - DiskSetDiskPathFilename(iDrive, sFilePath); -#if _DEBUG -// MessageBox(g_hFrameWindow,pFileName,pRegKey,MB_OK); -#endif - - // _tcscat(imagefilename,TEXT("MASTER.DSK")); // TODO: Should remember last disk by user g_bSaveDiskImage = false; // Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = "" DiskInsert(iDrive, sFilePath, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); g_bSaveDiskImage = true; } - //else MessageBox(g_hFrameWindow,"Reg Key/Value not found",pRegKey,MB_OK); } //=========================================================================== @@ -202,12 +207,23 @@ void Disk_SaveLastDiskImage(const int iDrive) if (!g_bSaveDiskImage) return; - const char *pFileName = DiskGetDiskPathFilename(iDrive).c_str(); + const char *pFileName = g_aFloppyDisk[iDrive].fullname; if (iDrive == DRIVE_1) RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_1, TRUE, pFileName); else RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_2, TRUE, pFileName); + + // + + char szPathName[MAX_PATH]; + strcpy(szPathName, DiskGetFullPathName(iDrive)); + if (_tcsrchr(szPathName, TEXT('\\'))) + { + char* pPathEnd = _tcsrchr(szPathName, TEXT('\\'))+1; + *pPathEnd = 0; + RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szPathName); + } } //=========================================================================== @@ -249,53 +265,6 @@ static Disk_Status_e GetDriveLightStatus(const int iDrive) return DISK_STATUS_OFF; } -//=========================================================================== - -static void GetImageTitle(LPCTSTR imagefilename, Disk_t* fptr) -{ - TCHAR imagetitle[ MAX_DISK_FULL_NAME+1 ]; - LPCTSTR startpos = imagefilename; - - // imagetitle = - if (_tcsrchr(startpos,TEXT('\\'))) - startpos = _tcsrchr(startpos,TEXT('\\'))+1; - - _tcsncpy(imagetitle,startpos,MAX_DISK_FULL_NAME); - imagetitle[MAX_DISK_FULL_NAME] = 0; - - // if imagetitle contains a lowercase char, then found=1 (why?) - BOOL found = 0; - int loop = 0; - while (imagetitle[loop] && !found) - { - if (IsCharLower(imagetitle[loop])) - found = 1; - else - loop++; - } - - if ((!found) && (loop > 2)) - CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1)); - - // fptr->fullname = - _tcsncpy( fptr->fullname, imagetitle, MAX_DISK_FULL_NAME ); - fptr->fullname[ MAX_DISK_FULL_NAME ] = 0; - - if (imagetitle[0]) - { - LPTSTR dot = imagetitle; - if (_tcsrchr(dot,TEXT('.'))) - dot = _tcsrchr(dot,TEXT('.')); - if (dot > imagetitle) - *dot = 0; - } - - // fptr->imagename = (ie. no extension) - _tcsncpy( fptr->imagename, imagetitle, MAX_DISK_IMAGE_NAME ); - fptr->imagename[ MAX_DISK_IMAGE_NAME ] = 0; -} - - //=========================================================================== static bool IsDriveValid(const int iDrive) @@ -331,8 +300,9 @@ static void ReadTrack(const int iDrive) if (pFloppy->trackimage && pFloppy->imagehandle) { - LOG_DISK("read track %2X%s\r", pFloppy->track, (pFloppy->phase & 1) ? ".5" : ""); - +#if LOG_DISK_TRACKS + LOG_DISK("track $%02X%s read\r\n", pFloppy->track, (pFloppy->phase & 1) ? ".5" : " "); +#endif ImageReadTrack( pFloppy->imagehandle, pFloppy->track, @@ -370,7 +340,6 @@ static void RemoveDisk(const int iDrive) memset( pFloppy->imagename, 0, MAX_DISK_IMAGE_NAME+1 ); memset( pFloppy->fullname , 0, MAX_DISK_FULL_NAME +1 ); pFloppy->strFilenameInZip = ""; - DiskSetDiskPathFilename(iDrive, ""); Disk_SaveLastDiskImage( iDrive ); Video_ResetScreenshotCounter( NULL ); @@ -389,12 +358,17 @@ static void WriteTrack(const int iDrive) return; if (pFloppy->trackimage && pFloppy->imagehandle) + { +#if LOG_DISK_TRACKS + LOG_DISK("track $%02X%s write\r\n", pFloppy->track, (pFloppy->phase & 0) ? ".5" : " "); // TODO: hard-coded to whole tracks - see below (nickw) +#endif ImageWriteTrack( pFloppy->imagehandle, pFloppy->track, - pFloppy->phase, + pFloppy->phase, // TODO: this should never be used; it's the current phase (half-track), not that of the track to be written (nickw) pFloppy->trackimage, - pFloppy->nibbles ); + pFloppy->nibbles); + } pFloppy->trackimagedirty = 0; } @@ -415,34 +389,34 @@ void DiskBoot(void) //=========================================================================== -static BYTE __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) { floppymotoron = address & 1; +#if LOG_DISK_MOTOR + LOG_DISK("motor %s\r\n", (floppymotoron) ? "on" : "off"); +#endif CheckSpinning(); - return MemReadFloatingBus(1, uExecutedCycles); // TC-TODO: Check b7 always set } //=========================================================================== -static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) { Disk_t * fptr = &g_aFloppyDisk[currdrive]; -#if 1 - int phase = (address >> 1) & 3; + int phase = (address >> 1) & 3; int phase_bit = (1 << phase); +#if 1 // update the magnet states if (address & 1) { // phase on phases |= phase_bit; - LOG_DISK("track %02X phases %X phase %d on address $C0E%X\r", fptr->phase, phases, phase, address & 0xF); } else { // phase off phases &= ~phase_bit; - LOG_DISK("track %02X phases %X phase %d off address $C0E%X\r", fptr->phase, phases, phase, address & 0xF); } // check for any stepping effect from a magnet @@ -463,7 +437,6 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG u const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); const int newtrack = (nNumTracksInImage == 0) ? 0 : MIN(nNumTracksInImage-1, fptr->phase >> 1); // (round half tracks down) - LOG_DISK("newtrack %2X%s\r", newtrack, (fptr->phase & 1) ? ".5" : ""); if (newtrack != fptr->track) { if (fptr->trackimage && fptr->trackimagedirty) @@ -478,31 +451,21 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG u // https://github.com/AppleWin/AppleWin/issues/201 FrameDrawDiskStatus( (HDC)0 ); } -#else // Old 1.13.1 code for Chessmaster 2000 to work! (see bug#18109) - const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); - if (address & 1) { - int phase = (address >> 1) & 3; - int direction = 0; - if (phase == ((fptr->phase+1) & 3)) - direction = 1; - if (phase == ((fptr->phase+3) & 3)) - direction = -1; - if (direction) { - fptr->phase = MAX(0,MIN(79,fptr->phase+direction)); - if (!(fptr->phase & 1)) { - int newtrack = MIN(nNumTracksInImage-1,fptr->phase >> 1); - if (newtrack != fptr->track) { - if (fptr->trackimage && fptr->trackimagedirty) - WriteTrack(currdrive); - fptr->track = newtrack; - fptr->trackimagedata = 0; - } - } - } - } +#else + // substitute alternate stepping code here to test +#endif +#if LOG_DISK_PHASES + LOG_DISK("track $%02X%s phases %d%d%d%d phase %d %s address $%4X\r\n", + fptr->phase >> 1, + (fptr->phase & 1) ? ".5" : " ", + (phases >> 3) & 1, + (phases >> 2) & 1, + (phases >> 1) & 1, + (phases >> 0) & 1, + phase, + (address & 1) ? "on " : "off", + address); #endif - return ((address & 0xF) == 0) ? 0xFF // TC-TODO: Check why $C0E0 only returns 0xFF - : MemReadFloatingBus(1, uExecutedCycles); // TC-TODO: Check b7 always set } //=========================================================================== @@ -520,13 +483,12 @@ void DiskDestroy(void) //=========================================================================== -static BYTE __stdcall DiskEnable(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskEnable(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) { currdrive = address & 1; g_aFloppyDisk[!currdrive].spinning = 0; g_aFloppyDisk[!currdrive].writelight = 0; CheckSpinning(); - return MemReadFloatingBus(uExecutedCycles); } //=========================================================================== @@ -558,6 +520,11 @@ LPCTSTR DiskGetFullDiskFilename(const int iDrive) return DiskGetFullName(iDrive); } +static LPCTSTR DiskGetFullPathName(const int iDrive) +{ + return ImageGetPathname(g_aFloppyDisk[iDrive].imagehandle); +} + // Return the imagename // . Used by Drive Button's icons & Property Sheet Page (Save snapshot) LPCTSTR DiskGetBaseName(const int iDrive) @@ -581,7 +548,7 @@ void DiskInitialize(void) { int loop = NUM_DRIVES; while (loop--) - ZeroMemory(&g_aFloppyDisk[loop],sizeof(Disk_t )); + ZeroMemory(&g_aFloppyDisk[loop], sizeof(Disk_t)); TCHAR imagefilename[MAX_PATH]; _tcscpy(imagefilename,g_sProgramDir); @@ -611,10 +578,20 @@ ImageError_e DiskInsert(const int iDrive, LPCTSTR pszImageFilename, const bool b else fptr->bWriteProtected = bForceWriteProtected ? true : (dwAttributes & FILE_ATTRIBUTE_READONLY); - // Check if image is being used by the other HDD, and unplug it in order to be swapped - std::string otherDisk = DiskGetDiskPathFilename(!iDrive); - if (!strcmp(otherDisk.c_str(), pszImageFilename)) { - DiskEject(!iDrive); + // Check if image is being used by the other drive, and if so remove it in order so it can be swapped + { + const char* pszOtherPathname = DiskGetFullPathName(!iDrive); + + char szCurrentPathname[MAX_PATH]; + DWORD uNameLen = GetFullPathName(pszImageFilename, MAX_PATH, szCurrentPathname, NULL); + if (uNameLen == 0 || uNameLen >= MAX_PATH) + strcpy_s(szCurrentPathname, MAX_PATH, pszImageFilename); + + if (!strcmp(pszOtherPathname, szCurrentPathname)) + { + DiskEject(!iDrive); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + } } ImageError_e Error = ImageOpen(pszImageFilename, @@ -637,19 +614,15 @@ ImageError_e DiskInsert(const int iDrive, LPCTSTR pszImageFilename, const bool b if (Error == eIMAGE_ERROR_NONE) { - GetImageTitle(pszImageFilename, fptr); - - DiskSetDiskPathFilename(iDrive, pszImageFilename); - - //MessageBox( g_hFrameWindow, imagefilename, fptr->imagename, MB_OK ); - Video_ResetScreenshotCounter( fptr->imagename ); + GetImageTitle(pszImageFilename, fptr->imagename, fptr->fullname); + Video_ResetScreenshotCounter(fptr->imagename); } else { - Video_ResetScreenshotCounter( NULL ); + Video_ResetScreenshotCounter(NULL); } - Disk_SaveLastDiskImage( iDrive ); + Disk_SaveLastDiskImage(iDrive); return Error; } @@ -730,6 +703,13 @@ void DiskNotifyInvalidImage(const int iDrive, LPCTSTR pszImageFilename, const Im pszImageFilename); break; + case eIMAGE_ERROR_FAILED_TO_GET_PATHNAME: + wsprintf( + szBuffer, + TEXT("Unable to GetFullPathName() for the file: %s."), + pszImageFilename); + break; + default: // IGNORE OTHER ERRORS SILENTLY return; @@ -793,8 +773,9 @@ bool Disk_IsDriveEmpty(const int iDrive) //=========================================================================== -static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULONG) +static void __stdcall DiskReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { + /* floppyloadmode = 0; */ Disk_t * fptr = &g_aFloppyDisk[currdrive]; diskaccessed = 1; @@ -803,32 +784,23 @@ static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULON ReadTrack(currdrive); if (!fptr->trackimagedata) - return 0xFF; - - BYTE result = 0; - - if (!floppywritemode || !fptr->bWriteProtected) { - if (floppywritemode) - { - if (floppylatch & 0x80) - { - *(fptr->trackimage+fptr->byte) = floppylatch; - fptr->trackimagedirty = 1; - } - else - { - return 0; - } - } - else - { - result = *(fptr->trackimage+fptr->byte); - } + floppylatch = 0xFF; + return; } - if (0) - { LOG_DISK("nib %4X = %2X\r", fptr->byte, result); } + if (!floppywritemode) + { + floppylatch = *(fptr->trackimage + fptr->byte); +#if LOG_DISK_NIBBLES + LOG_DISK("read %4X = %2X\r\n", fptr->byte, floppylatch); +#endif + } + else if ((floppylatch & 0x80) && !fptr->bWriteProtected) // && floppywritemode + { + *(fptr->trackimage + fptr->byte) = floppylatch; + fptr->trackimagedirty = 1; + } if (++fptr->byte >= fptr->nibbles) fptr->byte = 0; @@ -838,8 +810,6 @@ static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULON // NB. Prevent flooding of forcing UI to redraw!!! if( ((fptr->byte) & 0xFF) == 0 ) FrameDrawDiskStatus( (HDC)0 ); - - return result; } //=========================================================================== @@ -852,7 +822,7 @@ void DiskReset(void) //=========================================================================== -void DiskSelectImage(const int iDrive, LPSTR pszFilename) +static bool DiskSelectImage(const int iDrive, LPCSTR pszFilename) { TCHAR directory[MAX_PATH] = TEXT(""); TCHAR filename[MAX_PATH] = TEXT(""); @@ -880,6 +850,8 @@ void DiskSelectImage(const int iDrive, LPSTR pszFilename) ofn.Flags = OFN_PATHMUSTEXIST; ofn.lpstrTitle = title; + bool bRes = false; + if (GetOpenFileName(&ofn)) { if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension]) @@ -888,16 +860,15 @@ void DiskSelectImage(const int iDrive, LPSTR pszFilename) ImageError_e Error = DiskInsert(iDrive, filename, ofn.Flags & OFN_READONLY, IMAGE_CREATE); if (Error == eIMAGE_ERROR_NONE) { - DiskSetDiskPathFilename(iDrive, filename); - filename[ofn.nFileOffset] = 0; - if (_tcsicmp(directory, filename)) - RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, filename); + bRes = true; } else { DiskNotifyInvalidImage(iDrive, filename, Error); } } + + return bRes; } //=========================================================================== @@ -909,24 +880,31 @@ void DiskSelect(const int iDrive) //=========================================================================== -static BYTE __stdcall DiskSetLatchValue(WORD, WORD, BYTE write, BYTE value, ULONG) -{ - if (write) - floppylatch = value; - return floppylatch; +static void __stdcall DiskLoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG) { + /* floppyloadmode = 1; */ + if (!write) + { + if (floppymotoron && !floppywritemode) + { + // phase 1 on also forces write protect in the Disk II drive (UTA2E page 9-7) but we don't implement that + if (g_aFloppyDisk[currdrive].bWriteProtected) + floppylatch |= 0x80; + else + floppylatch &= 0x7F; + } + } } //=========================================================================== -static BYTE __stdcall DiskSetReadMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskSetReadMode(WORD, WORD, BYTE, BYTE, ULONG) { floppywritemode = 0; - return MemReadFloatingBus(g_aFloppyDisk[currdrive].bWriteProtected, uExecutedCycles); } //=========================================================================== -static BYTE __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) { floppywritemode = 1; BOOL modechange = !g_aFloppyDisk[currdrive].writelight; @@ -936,8 +914,6 @@ static BYTE __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCy //FrameRefreshStatus(DRAW_LEDS); FrameDrawDiskLEDS( (HDC)0 ); } - - return MemReadFloatingBus(1, uExecutedCycles); // TC-TODO: Check b7 always set } //=========================================================================== @@ -1032,121 +1008,88 @@ void DiskLoadRom(LPBYTE pCxRomPeripheral, UINT uSlot) memcpy(pCxRomPeripheral + uSlot*APPLE_SLOT_SIZE, pData, DISK2_FW_SIZE); - // NB. We used to disable the track stepping delay in the Disk II controller firmware by + // Note: We used to disable the track stepping delay in the Disk II controller firmware by // patching $C64C with $A9,$00,$EA. Now not doing this since: // . Authentic Speed should be authentic // . Enhanced Speed runs emulation unthrottled, so removing the delay has negligible effect // . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick) - // . In this case we can patch to compensate for an ADC or EOR checksum but not both + // . In this case we can patch to compensate for an ADC or EOR checksum but not both (nickw) RegisterIoHandler(uSlot, Disk_IORead, Disk_IOWrite, NULL, NULL, NULL, NULL); + + g_uSlot = uSlot; } //=========================================================================== static BYTE __stdcall Disk_IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { - addr &= 0xFF; - - switch (addr & 0xf) + switch (addr & 0xF) { - case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); + case 0x0: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x1: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x2: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x3: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x4: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x5: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x6: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x7: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x8: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x9: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xA: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xB: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xC: DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xD: DiskLoadWriteProtect(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xE: DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xF: DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); break; } - return 0; + // only even addresses return the latch (UTA2E Table 9.1) + if (!(addr & 1)) + return floppylatch; + else + return MemReadFloatingBus(nCyclesLeft); } static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { - addr &= 0xFF; - - switch (addr & 0xf) + switch (addr & 0xF) { - case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); + case 0x0: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x1: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x2: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x3: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x4: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x5: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x6: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x7: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x8: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x9: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xA: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xB: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xC: DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xD: DiskLoadWriteProtect(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xE: DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xF: DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); break; } + // any address writes the latch via sequencer LD command (74LS323 datasheet) + if (floppywritemode /* && floppyloadmode */) + { + floppylatch = d; + } return 0; } //=========================================================================== -DWORD DiskGetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot) +int DiskSetSnapshot_v1(const SS_CARD_DISK2* const pSS) { - pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2); - pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,2); + if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion > MAKE_VERSION(1,0,0,2)) + return -1; - pSS->Hdr.dwSlot = dwSlot; - pSS->Hdr.dwType = CT_Disk2; - - pSS->phases = phases; // new in 1.0.0.2 disk snapshots - pSS->currdrive = currdrive; // this was an int in 1.0.0.1 disk snapshots - pSS->diskaccessed = diskaccessed; - pSS->enhancedisk = enhancedisk; - pSS->floppylatch = floppylatch; - pSS->floppymotoron = floppymotoron; - pSS->floppywritemode = floppywritemode; - - for(UINT i=0; iUnit[i].szFileName, g_aFloppyDisk[i].fullname); - pSS->Unit[i].track = g_aFloppyDisk[i].track; - pSS->Unit[i].phase = g_aFloppyDisk[i].phase; - pSS->Unit[i].byte = g_aFloppyDisk[i].byte; - pSS->Unit[i].writeprotected = g_aFloppyDisk[i].bWriteProtected ? TRUE : FALSE; - pSS->Unit[i].trackimagedata = g_aFloppyDisk[i].trackimagedata; - pSS->Unit[i].trackimagedirty = g_aFloppyDisk[i].trackimagedirty; - pSS->Unit[i].spinning = g_aFloppyDisk[i].spinning; - pSS->Unit[i].writelight = g_aFloppyDisk[i].writelight; - pSS->Unit[i].nibbles = g_aFloppyDisk[i].nibbles; - - if(g_aFloppyDisk[i].trackimage) - memcpy(pSS->Unit[i].nTrack, g_aFloppyDisk[i].trackimage, NIBBLES_PER_TRACK); - else - memset(pSS->Unit[i].nTrack, 0, NIBBLES_PER_TRACK); - } - - return 0; -} - -DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/) -{ - if(pSS->Hdr.UnitHdr.dwVersion > MAKE_VERSION(1,0,0,2)) - { - return -1; - } - - phases = pSS->phases; // new in 1.0.0.2 disk snapshots - currdrive = pSS->currdrive; // this was an int in 1.0.0.1 disk snapshots + phases = pSS->phases; + currdrive = pSS->currdrive; diskaccessed = pSS->diskaccessed; enhancedisk = pSS->enhancedisk; floppylatch = pSS->floppylatch; @@ -1157,7 +1100,7 @@ DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/) for(UINT i=0; i pTrack( new BYTE [NIBBLES_PER_TRACK] ); + memset(pTrack.get(), 0, NIBBLES_PER_TRACK); + if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_TRACK_IMAGE)) + { + yamlLoadHelper.LoadMemory(pTrack.get(), NIBBLES_PER_TRACK); + yamlLoadHelper.PopMap(); + } + + yamlLoadHelper.PopMap(); + + // + + if (!filename.empty() && !bImageError) + { + if ((g_aFloppyDisk[unit].trackimage == NULL) && g_aFloppyDisk[unit].nibbles) + AllocTrack(unit); + + if (g_aFloppyDisk[unit].trackimage == NULL) + bImageError = true; + else + memcpy(g_aFloppyDisk[unit].trackimage, pTrack.get(), NIBBLES_PER_TRACK); + } + + if (bImageError) + { + g_aFloppyDisk[unit].trackimagedata = 0; + g_aFloppyDisk[unit].trackimagedirty = 0; + g_aFloppyDisk[unit].nibbles = 0; + } +} + +bool DiskLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 6) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + phases = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASES); + currdrive = yamlLoadHelper.LoadUint(SS_YAML_KEY_CURRENT_DRIVE); + diskaccessed = yamlLoadHelper.LoadBool(SS_YAML_KEY_DISK_ACCESSED); + enhancedisk = yamlLoadHelper.LoadBool(SS_YAML_KEY_ENHANCE_DISK); + floppylatch = yamlLoadHelper.LoadUint(SS_YAML_KEY_FLOPPY_LATCH); + floppymotoron = yamlLoadHelper.LoadBool(SS_YAML_KEY_FLOPPY_MOTOR_ON); + floppywritemode = yamlLoadHelper.LoadBool(SS_YAML_KEY_FLOPPY_WRITE_MODE); + + // Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1 + for(UINT i=0; ibWriteProtected = *pWriteProtected_; + ZeroMemory(*hDiskImage, sizeof(ImageInfo)); + ImageInfo* pImageInfo = (ImageInfo*) *hDiskImage; + pImageInfo->bWriteProtected = *pWriteProtected; ImageError_e Err = sg_DiskImageHelper.Open(pszImageFilename, pImageInfo, bCreateIfNecessary, strFilenameInZip); - if (pImageInfo->pImageType != NULL && Err == eIMAGE_ERROR_NONE && pImageInfo->pImageType->GetType() == eImageHDV) - Err = eIMAGE_ERROR_UNSUPPORTED_HDV; - if (Err != eIMAGE_ERROR_NONE) { - ImageClose(*hDiskImage_, true); - *hDiskImage_ = (HIMAGE)0; + ImageClose(*hDiskImage, true); + *hDiskImage = (HIMAGE)0; + return Err; + } + + if (pImageInfo->pImageType && pImageInfo->pImageType->GetType() == eImageHDV) + { + if (bExpectFloppy) + Err = eIMAGE_ERROR_UNSUPPORTED_HDV; return Err; } @@ -76,7 +80,7 @@ ImageError_e ImageOpen( LPCTSTR pszImageFilename, for (UINT uTrack = 0; uTrack < pImageInfo->uNumTracks; uTrack++) pImageInfo->ValidTrack[uTrack] = (pImageInfo->uImageSize > 0) ? 1 : 0; - *pWriteProtected_ = pImageInfo->bWriteProtected; + *pWriteProtected = pImageInfo->bWriteProtected; return eIMAGE_ERROR_NONE; } @@ -185,6 +189,36 @@ void ImageWriteTrack( const HIMAGE hDiskImage, //=========================================================================== +bool ImageReadBlock( const HIMAGE hDiskImage, + UINT nBlock, + LPBYTE pBlockBuffer) +{ + ImageInfo* ptr = (ImageInfo*) hDiskImage; + + bool bRes = false; + if (ptr->pImageType->AllowRW()) + bRes = ptr->pImageType->Read(ptr, nBlock, pBlockBuffer); + + return bRes; +} + +//=========================================================================== + +bool ImageWriteBlock( const HIMAGE hDiskImage, + UINT nBlock, + LPBYTE pBlockBuffer) +{ + ImageInfo* ptr = (ImageInfo*) hDiskImage; + + bool bRes = false; + if (ptr->pImageType->AllowRW() && !ptr->bWriteProtected) + bRes = ptr->pImageType->Write(ptr, nBlock, pBlockBuffer); + + return bRes; +} + +//=========================================================================== + int ImageGetNumTracks(const HIMAGE hDiskImage) { ImageInfo* ptr = (ImageInfo*) hDiskImage; @@ -202,3 +236,60 @@ bool ImageIsMultiFileZip(const HIMAGE hDiskImage) ImageInfo* ptr = (ImageInfo*) hDiskImage; return ptr ? (ptr->uNumEntriesInZip > 1) : false; } + +const char* ImageGetPathname(const HIMAGE hDiskImage) +{ + static char* szEmpty = ""; + ImageInfo* ptr = (ImageInfo*) hDiskImage; + return ptr ? ptr->szFilename : szEmpty; +} + +UINT ImageGetImageSize(const HIMAGE hDiskImage) +{ + ImageInfo* ptr = (ImageInfo*) hDiskImage; + return ptr ? ptr->uImageSize : 0; +} + +void GetImageTitle(LPCTSTR pPathname, TCHAR* pImageName, TCHAR* pFullName) +{ + TCHAR imagetitle[ MAX_DISK_FULL_NAME+1 ]; + LPCTSTR startpos = pPathname; + + // imagetitle = + if (_tcsrchr(startpos, TEXT('\\'))) + startpos = _tcsrchr(startpos, TEXT('\\'))+1; + + _tcsncpy(imagetitle, startpos, MAX_DISK_FULL_NAME); + imagetitle[MAX_DISK_FULL_NAME] = 0; + + // if imagetitle contains a lowercase char, then found=1 (why?) + BOOL found = 0; + int loop = 0; + while (imagetitle[loop] && !found) + { + if (IsCharLower(imagetitle[loop])) + found = 1; + else + loop++; + } + + if ((!found) && (loop > 2)) + CharLowerBuff(imagetitle+1, _tcslen(imagetitle+1)); + + // pFullName = + _tcsncpy( pFullName, imagetitle, MAX_DISK_FULL_NAME ); + pFullName[ MAX_DISK_FULL_NAME ] = 0; + + if (imagetitle[0]) + { + LPTSTR dot = imagetitle; + if (_tcsrchr(dot, TEXT('.'))) + dot = _tcsrchr(dot, TEXT('.')); + if (dot > imagetitle) + *dot = 0; + } + + // pImageName = (ie. no extension) + _tcsncpy( pImageName, imagetitle, MAX_DISK_IMAGE_NAME ); + pImageName[ MAX_DISK_IMAGE_NAME ] = 0; +} diff --git a/source/DiskImage.h b/source/DiskImage.h index b712399f..73b5bd4d 100644 --- a/source/DiskImage.h +++ b/source/DiskImage.h @@ -55,9 +55,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA eIMAGE_ERROR_UNABLE_TO_OPEN, eIMAGE_ERROR_UNABLE_TO_OPEN_GZ, eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP, + eIMAGE_ERROR_FAILED_TO_GET_PATHNAME, }; -ImageError_e ImageOpen(LPCTSTR pszImageFilename, HIMAGE* hDiskImage_, bool* pWriteProtected_, const bool bCreateIfNecessary, std::string& strFilenameInZip); + const int MAX_DISK_IMAGE_NAME = 15; + const int MAX_DISK_FULL_NAME = 127; + + +ImageError_e ImageOpen(LPCTSTR pszImageFilename, HIMAGE* hDiskImage, bool* pWriteProtected, const bool bCreateIfNecessary, std::string& strFilenameInZip, const bool bExpectFloppy=true); void ImageClose(const HIMAGE hDiskImage, const bool bOpenError=false); BOOL ImageBoot(const HIMAGE hDiskImage); void ImageDestroy(void); @@ -65,7 +70,13 @@ void ImageInitialize(void); void ImageReadTrack(const HIMAGE hDiskImage, int nTrack, int nQuarterTrack, LPBYTE pTrackImageBuffer, int* pNibbles); void ImageWriteTrack(const HIMAGE hDiskImage, int nTrack, int nQuarterTrack, LPBYTE pTrackImage, int nNibbles); +bool ImageReadBlock(const HIMAGE hDiskImage, UINT nBlock, LPBYTE pBlockBuffer); +bool ImageWriteBlock(const HIMAGE hDiskImage, UINT nBlock, LPBYTE pBlockBuffer); int ImageGetNumTracks(const HIMAGE hDiskImage); bool ImageIsWriteProtected(const HIMAGE hDiskImage); bool ImageIsMultiFileZip(const HIMAGE hDiskImage); +const char* ImageGetPathname(const HIMAGE hDiskImage); +UINT ImageGetImageSize(const HIMAGE hDiskImage); + +void GetImageTitle(LPCTSTR pPathname, TCHAR* pImageName, TCHAR* pFullName); diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp index 4eeef4a8..c4e8cb26 100644 --- a/source/DiskImageHelper.cpp +++ b/source/DiskImageHelper.cpp @@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "stdafx.h" -#include "Structs.h" #include "Common.h" #include "zlib.h" @@ -436,7 +435,7 @@ void CImageBase::DenibblizeTrack(LPBYTE trackimage, SectorOrder_e SectorOrder, i offset = 0; } - if ((bytenum == 3) && (byteval[1] = 0xAA)) + if ((bytenum == 3) && (byteval[1] == 0xAA)) { int loop = 0; int tempoffset = offset; @@ -1435,7 +1434,9 @@ ImageError_e CImageHelperBase::Open( LPCTSTR pszImageFilename, if (Err != eIMAGE_ERROR_NONE) return Err; - _tcsncpy(pImageInfo->szFilename, pszImageFilename, MAX_PATH); + DWORD uNameLen = GetFullPathName(pszImageFilename, MAX_PATH, pImageInfo->szFilename, NULL); + if (uNameLen == 0 || uNameLen >= MAX_PATH) + Err = eIMAGE_ERROR_FAILED_TO_GET_PATHNAME; return eIMAGE_ERROR_NONE; } @@ -1453,9 +1454,10 @@ void CImageHelperBase::Close(ImageInfo* pImageInfo, const bool bDeleteFile) if (bDeleteFile) { DeleteFile(pImageInfo->szFilename); - pImageInfo->szFilename[0] = 0; } + pImageInfo->szFilename[0] = 0; + delete [] pImageInfo->pImageBuffer; pImageInfo->pImageBuffer = NULL; } diff --git a/source/Frame.cpp b/source/Frame.cpp index 8bbd0783..e590b92c 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Mockingboard.h" #include "MouseInterface.h" #include "ParallelPrinter.h" +#include "Pravets.h" #include "Registry.h" #include "SaveState.h" #include "SerialComms.h" @@ -183,7 +184,7 @@ static bool g_bFullScreen32Bit = true; // Updates g_pAppTitle // ==================================================================== -void GetAppleWindowTitle() +static void GetAppleWindowTitle() { g_pAppTitle = g_pAppleWindowTitle; @@ -568,6 +569,7 @@ static void DrawFrameWindow () DebugDisplay(1); else // Win7: In fullscreen mode with 1 redraw the screen doesn't get redrawn. + // TC: 07/01/2015: Tryed with MP's double-buffered DX full-screen code, but still the same. //VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) //VideoRefreshScreen(0); VideoRedrawScreen(); @@ -622,6 +624,9 @@ void FrameDrawDiskLEDS( HDC passdc ) //=========================================================================== void FrameDrawDiskStatus( HDC passdc ) { + if (mem == NULL) + return; + // We use the actual drive since probing from memory doesn't tell us anything we don't already know. // DOS3.3 ProDOS // Drive $B7EA $BE3D @@ -764,6 +769,14 @@ void FrameDrawDiskStatus( HDC passdc ) //=========================================================================== static void DrawStatusArea (HDC passdc, int drawflags) { + if (g_hFrameWindow == NULL) + { + // TC: Fix drawing of drive buttons before frame created: + // . Main init loop: LoadConfiguration() called before FrameCreateWindow(), eg: + // LoadConfiguration() -> Disk_LoadLastDiskImage() -> DiskInsert() -> FrameRefreshStatus() + return; + } + FrameReleaseDC(); HDC dc = (passdc ? passdc : GetDC(g_hFrameWindow)); int x = buttonx; @@ -1025,7 +1038,7 @@ LRESULT CALLBACK FrameWndProc ( if (!restart) { DiskDestroy(); ImageDestroy(); - HD_Cleanup(); + HD_Destroy(); } PrintDestroy(); sg_SSC.CommDestroy(); @@ -1314,7 +1327,7 @@ LRESULT CALLBACK FrameWndProc ( { RevealCursor(); } - else if (g_nAppMode == MODE_RUNNING) + else if (g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING) { if (!sg_Mouse.IsEnabled()) { @@ -1391,7 +1404,7 @@ LRESULT CALLBACK FrameWndProc ( DrawCrosshairs(x,y); JoySetPosition(x-viewportx-2, g_nViewportCX-4, y-viewporty-2, g_nViewportCY-4); } - else if (sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING)) + else if (sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING)) { if (g_bLastCursorInAppleViewport) break; @@ -1422,7 +1435,7 @@ LRESULT CALLBACK FrameWndProc ( if (wparam == IDEVENT_TIMER_MOUSE) { // NB. Need to check /g_bAppActive/ since WM_TIMER events still occur after AppleWin app has lost focus - if (g_bAppActive && sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING)) + if (g_bAppActive && sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING)) { if (!g_bLastCursorInAppleViewport) break; @@ -1973,12 +1986,15 @@ void RelayEvent (UINT message, WPARAM wparam, LPARAM lparam) { } //=========================================================================== + +// todo: consolidate CtrlReset() and ResetMachineState() void ResetMachineState () { DiskReset(); // Set floppymotoron=0 g_bFullSpeed = 0; // Might've hit reset in middle of InternalCpuExecute() - so beep may get (partially) muted MemReset(); + PravetsReset(); DiskBoot(); VideoResetState(); sg_SSC.CommReset(); @@ -1987,7 +2003,7 @@ void ResetMachineState () MB_Reset(); SpkrReset(); sg_Mouse.Reset(); - g_ActiveCPU = CPU_6502; + SetActiveCpu( GetMainCpu() ); #ifdef USE_SPEECH_API g_Speech.Reset(); #endif @@ -1997,12 +2013,15 @@ void ResetMachineState () //=========================================================================== + +// todo: consolidate CtrlReset() and ResetMachineState() void CtrlReset() { // Ctrl+Reset - TODO: This is a terrible place for this code! if (!IS_APPLE2) MemResetPaging(); + PravetsReset(); DiskReset(); KeybReset(); if (!IS_APPLE2) @@ -2468,7 +2487,6 @@ void FrameSetCursorPosByMousePos() int iY, iMinY, iMaxY; sg_Mouse.GetXY(iX, iMinX, iMaxX, iY, iMinY, iMaxY); - _ASSERT(iMinX == 0 && iMinY == 0); float fScaleX = (float)(iX-iMinX) / ((float)(iMaxX-iMinX)); float fScaleY = (float)(iY-iMinY) / ((float)(iMaxY-iMinY)); @@ -2504,7 +2522,6 @@ static void FrameSetCursorPosByMousePos(int x, int y, int dx, int dy, bool bLeav int iX, iMinX, iMaxX; int iY, iMinY, iMaxY; sg_Mouse.GetXY(iX, iMinX, iMaxX, iY, iMinY, iMaxY); - _ASSERT(iMinX == 0 && iMinY == 0); if (bLeavingAppleScreen) { @@ -2624,3 +2641,17 @@ void GetViewportCXCY(int& nViewportCX, int& nViewportCY) nViewportCX = g_nViewportCX; nViewportCY = g_nViewportCY; } + +// Call all funcs with dependency on g_Apple2Type +void FrameUpdateApple2Type(void) +{ + DeleteGdiObjects(); + CreateGdiObjects(); + + // DRAW_TITLE : calls GetAppleWindowTitle() + // DRAW_LEDS : update LEDs (eg. CapsLock varies on Apple2 type) + DrawStatusArea( (HDC)0, DRAW_TITLE|DRAW_LEDS ); + + // Draw buttons & call DrawStatusArea(DRAW_BACKGROUND | DRAW_LEDS | DRAW_DISK_STATUS) + DrawFrameWindow(); +} diff --git a/source/Frame.h b/source/Frame.h index 81f87278..e54f4187 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -59,6 +59,7 @@ void GetViewportCXCY(int& nViewportCX, int& nViewportCY); bool GetFullScreen32Bit(void); void SetFullScreen32Bit(bool b32Bit); + void FrameUpdateApple2Type(void); void FrameDrawDiskLEDS( HDC hdc ); void FrameDrawDiskStatus( HDC hdc ); diff --git a/source/Harddisk.cpp b/source/Harddisk.cpp index 3406140e..90b3a0bc 100644 --- a/source/Harddisk.cpp +++ b/source/Harddisk.cpp @@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth -Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "HardDisk.h" #include "Memory.h" #include "Registry.h" +#include "YamlHelper.h" #include "..\resource\resource.h" @@ -114,28 +115,29 @@ Overview struct HDD { // From Disk_t - TCHAR imagename[16]; // Not used - TCHAR fullname[128]; + TCHAR imagename[ MAX_DISK_IMAGE_NAME + 1 ]; // (ie. no extension) [not used] + TCHAR fullname[ MAX_DISK_FULL_NAME + 1 ]; // or + std::string strFilenameInZip; // "" or [not used] + HIMAGE imagehandle; // Init'd by HD_Insert() -> ImageOpen() + bool bWriteProtected; // Needed for ImageOpen() [otherwise not used] // BYTE hd_error; WORD hd_memblock; UINT hd_diskblock; WORD hd_buf_ptr; - BOOL hd_imageloaded; - BYTE hd_buf[HD_BLOCK_SIZE+1]; // Why +1? + bool hd_imageloaded; + BYTE hd_buf[HD_BLOCK_SIZE+1]; // Why +1? Probably for erroreous reads beyond the block size (ie. reads from I/O addr 0xC0F8) #if HD_LED Disk_Status_e hd_status_next; Disk_Status_e hd_status_prev; #endif - - ImageInfo Info; }; static bool g_bHD_RomLoaded = false; static bool g_bHD_Enabled = false; -static BYTE g_nHD_UnitNum = HARDDISK_1; +static BYTE g_nHD_UnitNum = HARDDISK_1<<7; // b7=unit // The HDD interface has a single Command register for both drives: // . ProDOS will write to Command before switching drives @@ -143,114 +145,96 @@ static BYTE g_nHD_Command; static HDD g_HardDisk[NUM_HARDDISKS] = {0}; +static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry static UINT g_uSlot = 7; static CHardDiskImageHelper sg_HardDiskImageHelper; //=========================================================================== +static void HD_SaveLastDiskImage(const int iDrive); + static void HD_CleanupDrive(const int iDrive) { - sg_HardDiskImageHelper.Close(&g_HardDisk[iDrive].Info, false); - - g_HardDisk[iDrive].hd_imageloaded = false; - g_HardDisk[iDrive].imagename[0] = 0; - g_HardDisk[iDrive].fullname[0] = 0; - g_HardDisk[iDrive].Info.szFilename[0] = 0; -} - -static ImageError_e ImageOpen( LPCTSTR pszImageFilename, - const int iDrive, - const bool bCreateIfNecessary, - std::string& strFilenameInZip) -{ - if (!pszImageFilename) - return eIMAGE_ERROR_BAD_POINTER; - - HDD* pHDD = &g_HardDisk[iDrive]; - ImageInfo* pImageInfo = &pHDD->Info; - pImageInfo->bWriteProtected = false; - - ImageError_e Err = sg_HardDiskImageHelper.Open(pszImageFilename, pImageInfo, bCreateIfNecessary, strFilenameInZip); - - if (Err != eIMAGE_ERROR_NONE) + if (g_HardDisk[iDrive].imagehandle) { - HD_CleanupDrive(iDrive); - return Err; + ImageClose(g_HardDisk[iDrive].imagehandle); + g_HardDisk[iDrive].imagehandle = (HIMAGE)0; } - return eIMAGE_ERROR_NONE; + g_HardDisk[iDrive].hd_imageloaded = false; + + g_HardDisk[iDrive].imagename[0] = 0; + g_HardDisk[iDrive].fullname[0] = 0; + g_HardDisk[iDrive].strFilenameInZip = ""; + + HD_SaveLastDiskImage(iDrive); } //----------------------------------------------------------------------------- -static void GetImageTitle(LPCTSTR pszImageFilename, HDD* pHardDrive) -{ - TCHAR imagetitle[128]; - LPCTSTR startpos = pszImageFilename; - - // imagetitle = - if (_tcsrchr(startpos,TEXT('\\'))) - startpos = _tcsrchr(startpos,TEXT('\\'))+1; - _tcsncpy(imagetitle,startpos,127); - imagetitle[127] = 0; - - // if imagetitle contains a lowercase char, then found=1 (why?) - BOOL found = 0; - int loop = 0; - while (imagetitle[loop] && !found) - { - if (IsCharLower(imagetitle[loop])) - found = 1; - else - loop++; - } - - if ((!found) && (loop > 2)) - CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1)); - - // hdptr->fullname = - _tcsncpy(pHardDrive->fullname,imagetitle,127); - pHardDrive->fullname[127] = 0; - - if (imagetitle[0]) - { - LPTSTR dot = imagetitle; - if (_tcsrchr(dot,TEXT('.'))) - dot = _tcsrchr(dot,TEXT('.')); - if (dot > imagetitle) - *dot = 0; - } - - // hdptr->imagename = (ie. no extension) - _tcsncpy(pHardDrive->imagename,imagetitle,15); - pHardDrive->imagename[15] = 0; -} - static void NotifyInvalidImage(TCHAR* pszImageFilename) { // TC: TO DO } -static BOOL HD_Load_Image(const int iDrive, LPCSTR pszImageFilename) +//=========================================================================== + +BOOL HD_Insert(const int iDrive, LPCTSTR pszImageFilename); + +void HD_LoadLastDiskImage(const int iDrive) { - const bool bCreateIfNecessary = false; // NB. Don't allow creation of HDV files - std::string strFilenameInZip; // TODO: Use this - ImageError_e Error = ImageOpen(pszImageFilename, iDrive, bCreateIfNecessary, strFilenameInZip); + _ASSERT(iDrive == HARDDISK_1 || iDrive == HARDDISK_2); - g_HardDisk[iDrive].hd_imageloaded = (Error == eIMAGE_ERROR_NONE); + char sFilePath[ MAX_PATH + 1]; + sFilePath[0] = 0; -#if HD_LED - g_HardDisk[iDrive].hd_status_next = DISK_STATUS_OFF; - g_HardDisk[iDrive].hd_status_prev = DISK_STATUS_OFF; -#endif + char *pRegKey = (iDrive == HARDDISK_1) + ? REGVALUE_PREF_LAST_HARDDISK_1 + : REGVALUE_PREF_LAST_HARDDISK_2; - return g_HardDisk[iDrive].hd_imageloaded; + if (RegLoadString(TEXT(REG_PREFS), pRegKey, 1, sFilePath, MAX_PATH)) + { + sFilePath[ MAX_PATH ] = 0; + + g_bSaveDiskImage = false; + // Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = "" // todo: update comment for HD func + HD_Insert(iDrive, sFilePath); + g_bSaveDiskImage = true; + } } //=========================================================================== -// everything below is global +static void HD_SaveLastDiskImage(const int iDrive) +{ + _ASSERT(iDrive == HARDDISK_1 || iDrive == HARDDISK_2); + + if (!g_bSaveDiskImage) + return; + + const char *pFileName = g_HardDisk[iDrive].fullname; + + if (iDrive == HARDDISK_1) + RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_HARDDISK_1, TRUE, pFileName); + else + RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_HARDDISK_2, TRUE, pFileName); + + // + + char szPathName[MAX_PATH]; + strcpy(szPathName, HD_GetFullPathName(iDrive)); + if (_tcsrchr(szPathName, TEXT('\\'))) + { + char* pPathEnd = _tcsrchr(szPathName, TEXT('\\'))+1; + *pPathEnd = 0; + RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, szPathName); + } +} + +//=========================================================================== + +// (Nearly) everything below is global static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); @@ -263,7 +247,8 @@ bool HD_CardIsEnabled(void) // Called by: // . LoadConfiguration() - Done at each restart -// . DiskDlg_OK() - When HD is enabled/disabled on UI +// . RestoreCurrentConfig() - Done when Config dialog is cancelled +// . Snapshot_LoadState_v2() - Done to default to disabled state void HD_SetEnabled(const bool bEnabled) { if(g_bHD_Enabled == bEnabled) @@ -298,17 +283,17 @@ LPCTSTR HD_GetFullName(const int iDrive) LPCTSTR HD_GetFullPathName(const int iDrive) { - return g_HardDisk[iDrive].Info.szFilename; + return ImageGetPathname(g_HardDisk[iDrive].imagehandle); } -static LPCTSTR HD_DiskGetBaseName (const int iDrive) // Not used +static LPCTSTR HD_DiskGetBaseName(const int iDrive) // Not used { return g_HardDisk[iDrive].imagename; } //------------------------------------- -VOID HD_Load_Rom(const LPBYTE pCxRomPeripheral, const UINT uSlot) +void HD_Load_Rom(const LPBYTE pCxRomPeripheral, const UINT uSlot) { if(!g_bHD_Enabled) return; @@ -336,46 +321,82 @@ VOID HD_Load_Rom(const LPBYTE pCxRomPeripheral, const UINT uSlot) RegisterIoHandler(g_uSlot, HD_IO_EMUL, HD_IO_EMUL, NULL, NULL, NULL, NULL); } -VOID HD_Cleanup(void) +void HD_Destroy(void) { - for(int i=HARDDISK_1; i= MAX_PATH) + strcpy_s(szCurrentPathname, MAX_PATH, pszImageFilename); + + if (!strcmp(pszOtherPathname, szCurrentPathname)) + { + HD_Unplug(!iDrive); + FrameRefreshStatus(DRAW_LEDS); + } } - BOOL bResult = HD_Load_Image(iDrive, pszImageFilename); + const bool bCreateIfNecessary = false; // NB. Don't allow creation of HDV files + const bool bExpectFloppy = false; + ImageError_e Error = ImageOpen(pszImageFilename, + &g_HardDisk[iDrive].imagehandle, + &g_HardDisk[iDrive].bWriteProtected, + bCreateIfNecessary, + g_HardDisk[iDrive].strFilenameInZip, // TODO: Use this + bExpectFloppy); - if (bResult) - GetImageTitle(pszImageFilename, &g_HardDisk[iDrive]); + g_HardDisk[iDrive].hd_imageloaded = (Error == eIMAGE_ERROR_NONE); - return bResult; +#if HD_LED + g_HardDisk[iDrive].hd_status_next = DISK_STATUS_OFF; + g_HardDisk[iDrive].hd_status_prev = DISK_STATUS_OFF; +#endif + + if (Error == eIMAGE_ERROR_NONE) + { + GetImageTitle(pszImageFilename, g_HardDisk[iDrive].imagename, g_HardDisk[iDrive].fullname); + } + + HD_SaveLastDiskImage(iDrive); + + return g_HardDisk[iDrive].hd_imageloaded; } -void HD_Select(const int iDrive) +static bool HD_SelectImage(const int iDrive, LPCSTR pszFilename) { TCHAR directory[MAX_PATH] = TEXT(""); TCHAR filename[MAX_PATH] = TEXT(""); TCHAR title[40]; + strcpy(filename, pszFilename); + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, directory, MAX_PATH); _tcscpy(title, TEXT("Select HDV Image For HDD ")); _tcscat(title, iDrive ? TEXT("2") : TEXT("1")); + _ASSERT(sizeof(OPENFILENAME) == sizeof(OPENFILENAME_NT4)); // Required for Win98/ME support (selected by _WIN32_WINNT=0x0400 in stdafx.h) + OPENFILENAME ofn; ZeroMemory(&ofn,sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); @@ -389,22 +410,29 @@ void HD_Select(const int iDrive) ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; // Don't allow creation & hide the read-only checkbox ofn.lpstrTitle = title; + bool bRes = false; + if (GetOpenFileName(&ofn)) { if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension]) _tcscat(filename,TEXT(".hdv")); - if (HD_InsertDisk(iDrive, filename)) + if (HD_Insert(iDrive, filename)) { - filename[ofn.nFileOffset] = 0; - if (_tcsicmp(directory, filename)) - RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, filename); + bRes = true; } else { NotifyInvalidImage(filename); } } + + return bRes; +} + +void HD_Select(const int iDrive) +{ + HD_SelectImage(iDrive, TEXT("")); } void HD_Unplug(const int iDrive) @@ -415,7 +443,7 @@ void HD_Unplug(const int iDrive) bool HD_IsDriveUnplugged(const int iDrive) { - return g_HardDisk[iDrive].hd_imageloaded == FALSE; + return g_HardDisk[iDrive].hd_imageloaded == false; } //----------------------------------------------------------------------------- @@ -450,33 +478,33 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG { default: case 0x00: //status - if (pHDD->Info.uImageSize == 0) + if (ImageGetImageSize(pHDD->imagehandle) == 0) { pHDD->hd_error = 1; r = DEVICE_IO_ERROR; } break; case 0x01: //read - if ((pHDD->hd_diskblock * HD_BLOCK_SIZE) < pHDD->Info.uImageSize) + if ((pHDD->hd_diskblock * HD_BLOCK_SIZE) < ImageGetImageSize(pHDD->imagehandle)) + { + bool bRes = ImageReadBlock(pHDD->imagehandle, pHDD->hd_diskblock, pHDD->hd_buf); + if (bRes) { - bool bRes = pHDD->Info.pImageType->Read(&pHDD->Info, pHDD->hd_diskblock, pHDD->hd_buf); - if (bRes) - { - pHDD->hd_error = 0; - r = 0; - pHDD->hd_buf_ptr = 0; - } - else - { - pHDD->hd_error = 1; - r = DEVICE_IO_ERROR; - } + pHDD->hd_error = 0; + r = 0; + pHDD->hd_buf_ptr = 0; } else { pHDD->hd_error = 1; r = DEVICE_IO_ERROR; } + } + else + { + pHDD->hd_error = 1; + r = DEVICE_IO_ERROR; + } break; case 0x02: //write { @@ -484,17 +512,17 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG pHDD->hd_status_next = DISK_STATUS_WRITE; #endif bool bRes = true; - const bool bAppendBlocks = (pHDD->hd_diskblock * HD_BLOCK_SIZE) >= pHDD->Info.uImageSize; + const bool bAppendBlocks = (pHDD->hd_diskblock * HD_BLOCK_SIZE) >= ImageGetImageSize(pHDD->imagehandle); if (bAppendBlocks) { ZeroMemory(pHDD->hd_buf, HD_BLOCK_SIZE); // Inefficient (especially for gzip/zip files!) - UINT uBlock = pHDD->Info.uImageSize / HD_BLOCK_SIZE; + UINT uBlock = ImageGetImageSize(pHDD->imagehandle) / HD_BLOCK_SIZE; while (uBlock < pHDD->hd_diskblock) { - bRes = pHDD->Info.pImageType->Write(&pHDD->Info, uBlock++, pHDD->hd_buf); + bRes = ImageWriteBlock(pHDD->imagehandle, uBlock++, pHDD->hd_buf); _ASSERT(bRes); if (!bRes) break; @@ -504,7 +532,7 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG MoveMemory(pHDD->hd_buf, mem+pHDD->hd_memblock, HD_BLOCK_SIZE); if (bRes) - bRes = pHDD->Info.pImageType->Write(&pHDD->Info, pHDD->hd_diskblock, pHDD->hd_buf); + bRes = ImageWriteBlock(pHDD->imagehandle, pHDD->hd_diskblock, pHDD->hd_buf); if (bRes) { @@ -560,7 +588,8 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG break; case 0xF8: r = pHDD->hd_buf[pHDD->hd_buf_ptr]; - pHDD->hd_buf_ptr++; + if (pHDD->hd_buf_ptr < sizeof(pHDD->hd_buf)-1) + pHDD->hd_buf_ptr++; break; default: #if HD_LED @@ -631,3 +660,156 @@ void HD_GetLightStatus (Disk_Status_e *pDisk1Status_) *pDisk1Status_ = DISK_STATUS_OFF; } } + +//=========================================================================== + +#define SS_YAML_VALUE_CARD_HDD "Generic HDD" + +#define SS_YAML_KEY_CURRENT_UNIT "Current Unit" +#define SS_YAML_KEY_COMMAND "Command" + +#define SS_YAML_KEY_HDDUNIT "Unit" +#define SS_YAML_KEY_FILENAME "Filename" +#define SS_YAML_KEY_ERROR "Error" +#define SS_YAML_KEY_MEMBLOCK "MemBlock" +#define SS_YAML_KEY_DISKBLOCK "DiskBlock" +#define SS_YAML_KEY_IMAGELOADED "ImageLoaded" +#define SS_YAML_KEY_STATUS_NEXT "Status Next" +#define SS_YAML_KEY_STATUS_PREV "Status Prev" +#define SS_YAML_KEY_BUF_PTR "Buffer Offset" +#define SS_YAML_KEY_BUF "Buffer" + +std::string HD_GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_HDD); + return name; +} + +static void HD_SaveSnapshotHDDUnit(YamlSaveHelper& yamlSaveHelper, UINT unit) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s%d:\n", SS_YAML_KEY_HDDUNIT, unit); + yamlSaveHelper.SaveString(SS_YAML_KEY_FILENAME, g_HardDisk[unit].fullname); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_ERROR, g_HardDisk[unit].hd_error); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_MEMBLOCK, g_HardDisk[unit].hd_memblock); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_DISKBLOCK, g_HardDisk[unit].hd_diskblock); + yamlSaveHelper.SaveBool(SS_YAML_KEY_IMAGELOADED, g_HardDisk[unit].hd_imageloaded); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STATUS_NEXT, g_HardDisk[unit].hd_status_next); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STATUS_PREV, g_HardDisk[unit].hd_status_prev); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_BUF_PTR, g_HardDisk[unit].hd_buf_ptr); + + // New label + { + YamlSaveHelper::Label buffer(yamlSaveHelper, "%s:\n", SS_YAML_KEY_BUF); + yamlSaveHelper.SaveMemory(g_HardDisk[unit].hd_buf, HD_BLOCK_SIZE); + } +} + +void HD_SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + if (!HD_CardIsEnabled()) + return; + + YamlSaveHelper::Slot slot(yamlSaveHelper, HD_GetSnapshotCardName(), g_uSlot, 1); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + yamlSaveHelper.Save("%s: %d # b7=unit\n", SS_YAML_KEY_CURRENT_UNIT, g_nHD_UnitNum); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, g_nHD_Command); + + HD_SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_1); + HD_SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_2); +} + +static bool HD_LoadSnapshotHDDUnit(YamlLoadHelper& yamlLoadHelper, UINT unit) +{ + std::string hddUnitName = std::string(SS_YAML_KEY_HDDUNIT) + (unit == HARDDISK_1 ? std::string("0") : std::string("1")); + if (!yamlLoadHelper.GetSubMap(hddUnitName)) + throw std::string("Card: Expected key: ") + hddUnitName; + + g_HardDisk[unit].fullname[0] = 0; + g_HardDisk[unit].imagename[0] = 0; + g_HardDisk[unit].hd_imageloaded = false; // Default to false (until image is successfully loaded below) + g_HardDisk[unit].hd_status_next = DISK_STATUS_OFF; + g_HardDisk[unit].hd_status_prev = DISK_STATUS_OFF; + + std::string filename = yamlLoadHelper.LoadString(SS_YAML_KEY_FILENAME); + g_HardDisk[unit].hd_error = yamlLoadHelper.LoadUint(SS_YAML_KEY_ERROR); + g_HardDisk[unit].hd_memblock = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMBLOCK); + g_HardDisk[unit].hd_diskblock = yamlLoadHelper.LoadUint(SS_YAML_KEY_DISKBLOCK); + yamlLoadHelper.LoadBool(SS_YAML_KEY_IMAGELOADED); // Consume + Disk_Status_e diskStatusNext = (Disk_Status_e) yamlLoadHelper.LoadUint(SS_YAML_KEY_STATUS_NEXT); + Disk_Status_e diskStatusPrev = (Disk_Status_e) yamlLoadHelper.LoadUint(SS_YAML_KEY_STATUS_PREV); + g_HardDisk[unit].hd_buf_ptr = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUF_PTR); + + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_BUF)) + throw hddUnitName + std::string(": Missing: ") + std::string(SS_YAML_KEY_BUF); + yamlLoadHelper.LoadMemory(g_HardDisk[unit].hd_buf, HD_BLOCK_SIZE); + + yamlLoadHelper.PopMap(); + yamlLoadHelper.PopMap(); + + // + + bool bResSelectImage = false; + + if (!filename.empty()) + { + DWORD dwAttributes = GetFileAttributes(filename.c_str()); + if (dwAttributes == INVALID_FILE_ATTRIBUTES) + { + // Get user to browse for file + bResSelectImage = HD_SelectImage(unit, filename.c_str()); + + dwAttributes = GetFileAttributes(filename.c_str()); + } + + bool bImageError = (dwAttributes == INVALID_FILE_ATTRIBUTES); + if (!bImageError) + { + if (!HD_Insert(unit, filename.c_str())) + bImageError = true; + + // HD_Insert() sets up: + // . imagename + // . fullname + // . hd_imageloaded + // . hd_status_next = DISK_STATUS_OFF + // . hd_status_prev = DISK_STATUS_OFF + + g_HardDisk[unit].hd_status_next = diskStatusNext; + g_HardDisk[unit].hd_status_prev = diskStatusPrev; + } + } + + return bResSelectImage; +} + +bool HD_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version, const std::string strSaveStatePath) +{ + if (slot != 7) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + g_nHD_UnitNum = yamlLoadHelper.LoadUint(SS_YAML_KEY_CURRENT_UNIT); // b7=unit + g_nHD_Command = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND); + + // Unplug all HDDs first in case HDD-2 is to be plugged in as HDD-1 + for (UINT i=0; i JN_JOYSTICK1) + return; + + joytype[num] = type; + + // Refresh centre positions whenever 'joytype' changes + JoySetTrim(JoyGetTrim(true) , true); + JoySetTrim(JoyGetTrim(false), false); +} + +DWORD JoyGetJoyType(UINT num) +{ + _ASSERT(num <= JN_JOYSTICK1); + if (num > JN_JOYSTICK1) + return J0C_DISABLED; + + return joytype[num]; +} + +//=========================================================================== + void JoySetTrim(short nValue, bool bAxisX) { if(bAxisX) @@ -824,14 +849,45 @@ void JoyportControl(const UINT uControl) //=========================================================================== -DWORD JoyGetSnapshot(SS_IO_Joystick* pSS) +void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle) { - pSS->g_nJoyCntrResetCycle = g_nJoyCntrResetCycle; - return 0; + g_nJoyCntrResetCycle = JoyCntrResetCycle; } -DWORD JoySetSnapshot(SS_IO_Joystick* pSS) +// + +#define SS_YAML_KEY_COUNTERRESETCYCLE "Counter Reset Cycle" +#define SS_YAML_KEY_JOY0TRIMX "Joystick0 TrimX" +#define SS_YAML_KEY_JOY0TRIMY "Joystick0 TrimY" +#define SS_YAML_KEY_JOY1TRIMX "Joystick1 TrimX" +#define SS_YAML_KEY_JOY1TRIMY "Joystick1 TrimY" + +static std::string JoyGetSnapshotStructName(void) { - g_nJoyCntrResetCycle = pSS->g_nJoyCntrResetCycle; - return 0; + static const std::string name("Joystick"); + return name; +} + +void JoySaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", JoyGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COUNTERRESETCYCLE, g_nJoyCntrResetCycle); + yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMX, JoyGetTrim(true)); + yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMY, JoyGetTrim(false)); + yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMX, 0); // not implemented yet + yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMY, 0); // not implemented yet +} + +void JoyLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(JoyGetSnapshotStructName())) + return; + + g_nJoyCntrResetCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COUNTERRESETCYCLE); + JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMX), true); + JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMY), false); + yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMX); // dump value + yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMY); // dump value + + yamlLoadHelper.PopMap(); } diff --git a/source/Joystick.h b/source/Joystick.h index 9889c2c9..517b9fcd 100644 --- a/source/Joystick.h +++ b/source/Joystick.h @@ -5,8 +5,6 @@ enum JOYNUM {JN_JOYSTICK0=0, JN_JOYSTICK1}; enum JOY0CHOICE {J0C_DISABLED=0, J0C_JOYSTICK1, J0C_KEYBD_CURSORS, J0C_KEYBD_NUMPAD, J0C_MOUSE, J0C_MAX}; enum JOY1CHOICE {J1C_DISABLED=0, J1C_JOYSTICK2, J1C_KEYBD_CURSORS, J1C_KEYBD_NUMPAD, J1C_MOUSE, J1C_MAX}; -extern DWORD joytype[2]; - enum {JOYSTICK_MODE_FLOATING=0, JOYSTICK_MODE_CENTERING}; // Joystick centering control void JoyInitialize(); @@ -21,11 +19,14 @@ BOOL JoyUsingKeyboard(); BOOL JoyUsingKeyboardCursors(); BOOL JoyUsingKeyboardNumpad(); void JoyDisableUsingMouse(); +void JoySetJoyType(UINT num, DWORD type); +DWORD JoyGetJoyType(UINT num); void JoySetTrim(short nValue, bool bAxisX); short JoyGetTrim(bool bAxisX); void JoyportControl(const UINT uControl); -DWORD JoyGetSnapshot(SS_IO_Joystick* pSS); -DWORD JoySetSnapshot(SS_IO_Joystick* pSS); +void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle); +void JoySaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 2b1e1727..936eb63b 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -31,7 +31,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "AppleWin.h" #include "Frame.h" #include "Keyboard.h" +#include "Pravets.h" #include "Tape.h" +#include "YamlHelper.h" static bool g_bKeybBufferEnable = false; @@ -50,7 +52,6 @@ static bool g_bCapsLock = true; //Caps lock key for Apple2 and Lat/Cyr lock for static bool g_bP8CapsLock = true; //Caps lock key of Pravets 8A/C static int lastvirtkey = 0; // Current PC keycode static BYTE keycode = 0; // Current Apple keycode -static DWORD keyboardqueries = 0; #ifdef KEY_OLD // Original @@ -160,14 +161,6 @@ BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode() return keycode; } -//=========================================================================== -DWORD KeybGetNumQueries () // Used in determining 'idleness' of Apple system -{ - DWORD result = keyboardqueries; - keyboardqueries = 0; - return result; -} - //=========================================================================== void KeybQueueKeypress (int key, BOOL bASCII) { @@ -425,10 +418,6 @@ static char ClipboardCurrChar(bool bIncPtr) BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) { - keyboardqueries++; - - // - if(g_bPasteFromClipboard) ClipboardInit(); @@ -463,10 +452,6 @@ BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) { - keyboardqueries++; - - // - if(g_bPasteFromClipboard) ClipboardInit(); @@ -516,16 +501,33 @@ void KeybToggleP8ACapsLock () //=========================================================================== -DWORD KeybGetSnapshot(SS_IO_Keyboard* pSS) +void KeybSetSnapshot_v1(const BYTE LastKey) { - pSS->keyboardqueries = keyboardqueries; - pSS->nLastKey = g_nLastKey; - return 0; + g_nLastKey = LastKey; } -DWORD KeybSetSnapshot(SS_IO_Keyboard* pSS) +// + +#define SS_YAML_KEY_LASTKEY "Last Key" + +static std::string KeybGetSnapshotStructName(void) { - keyboardqueries = pSS->keyboardqueries; - g_nLastKey = pSS->nLastKey; - return 0; + static const std::string name("Keyboard"); + return name; +} + +void KeybSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", KeybGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_LASTKEY, g_nLastKey); +} + +void KeybLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(KeybGetSnapshotStructName())) + return; + + g_nLastKey = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTKEY); + + yamlLoadHelper.PopMap(); } diff --git a/source/Keyboard.h b/source/Keyboard.h index 0010b677..f79cb203 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -11,12 +11,12 @@ bool KeybGetShiftStatus(); bool KeybGetCapsAllowed(); //For Pravets8A/C only void KeybUpdateCtrlShiftStatus(); BYTE KeybGetKeycode (); -DWORD KeybGetNumQueries (); void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); -DWORD KeybGetSnapshot(SS_IO_Keyboard* pSS); -DWORD KeybSetSnapshot(SS_IO_Keyboard* pSS); +void KeybSetSnapshot_v1(const BYTE LastKey); +void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall KeybReadData (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); BYTE __stdcall KeybReadFlag (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/Log.cpp b/source/Log.cpp index e277a56c..fb419b05 100644 --- a/source/Log.cpp +++ b/source/Log.cpp @@ -33,13 +33,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA void LogOutput(LPCTSTR format, ...) { - TCHAR output[256]; + TCHAR output[256]; - va_list args; - va_start(args, format); + va_list args; + va_start(args, format); - _vsntprintf(output, sizeof(output) - 1, format, args); - OutputDebugString(output); + _vsntprintf(output, sizeof(output) - 1, format, args); + OutputDebugString(output); } //--------------------------------------------------------------------------- @@ -51,11 +51,11 @@ void LogFileOutput(LPCTSTR format, ...) if (!g_fh) return; - TCHAR output[256]; + TCHAR output[256]; - va_list args; - va_start(args, format); + va_list args; + va_start(args, format); - _vsntprintf(output, sizeof(output) - 1, format, args); - fprintf(g_fh, output); + _vsntprintf(output, sizeof(output) - 1, format, args); + fprintf(g_fh, "%s", output); } diff --git a/source/Memory.cpp b/source/Memory.cpp index 56c36b00..5d2bcd18 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: Memory emulation * * Author: Various + * + * In comments, UTA2E is an abbreviation for a reference to "Understanding the Apple //e" by James Sather */ #include "StdAfx.h" @@ -42,6 +44,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NoSlotClock.h" #include "ParallelPrinter.h" #include "Registry.h" +#include "SAM.h" #include "SerialComms.h" #include "Speaker.h" #include "Tape.h" @@ -52,6 +55,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "..\resource\resource.h" #include "Configuration\PropertySheet.h" #include "Debugger\DebugDefs.h" +#include "YamlHelper.h" // Memory Flag #define MF_80STORE 0x00000001 @@ -170,7 +174,7 @@ iofunction IORead[256]; iofunction IOWrite[256]; static LPVOID SlotParameters[NUM_SLOTS]; -static BOOL lastwriteram = 0; +static BOOL lastwriteram = 0; // NB. redundant - only used in MemSetPaging(), where it's forced to 1 LPBYTE mem = NULL; @@ -194,12 +198,12 @@ static BOOL Pravets8charmode = 0; static CNoSlotClock g_NoSlotClock; #ifdef RAMWORKS -UINT g_uMaxExPages = 1; // user requested ram pages -static LPBYTE RWpages[128]; // pointers to RW memory banks +UINT g_uMaxExPages = 1; // user requested ram pages (default to 1 aux bank: so total = 128KB) +UINT g_uActiveBank = 0; // 0 = aux 64K for: //e extended 80 Col card, or //c +static LPBYTE RWpages[kMaxExMemoryBanks]; // pointers to RW memory banks #endif BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); -void UpdatePaging(BOOL initialize); //============================================================================= @@ -231,7 +235,7 @@ static BYTE __stdcall IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return VideoCheckVbl( nCyclesLeft ); // NTSC cleanup + case 0x9: return VideoCheckVbl(nCyclesLeft); case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); @@ -342,7 +346,7 @@ static BYTE __stdcall IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG { static byte CurrentKestroke = 0; CurrentKestroke = KeybGetKeycode(); - switch (addr & 0xf) + switch (addr & 0x7) // address bit 4 is ignored (UTA2E page 7-5) { //In Pravets8A/C if SETMODE (8bit character encoding) is enabled, bit6 in $C060 is 0; Else it is 1 //If (CAPS lOCK of Pravets8A/C is on or Shift is pressed) and (MODE is enabled), bit7 in $C000 is 1; Else it is 0 @@ -356,14 +360,6 @@ static BYTE __stdcall IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG case 0x5: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); //$C065 Analog input 1 case 0x6: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); //$C066 Analog input 2 case 0x7: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); //$C067 Analog input 3 - case 0x8: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } return 0; @@ -694,11 +690,6 @@ static void InitIoHandlers() // - IO_SELECT = 0; - IO_SELECT_InternalROM = 0; - g_eExpansionRomType = eExpRomNull; - g_uPeripheralRomSlot = 0; - for (i=0; i> 8) & 0xF; return (memshadow[0xD0+bank1page] == pMemBase+(0xC0+bank1page)*256) ? mem+offset+0x1000 // Return ptr to $Dxxx address - 'mem' has (a potentially dirty) 4K RAM BANK1 mapped in at $D000 @@ -1104,17 +1106,14 @@ LPBYTE MemGetCxRomPeripheral() //=========================================================================== +const UINT CxRomSize = 4*1024; +const UINT Apple2RomSize = 12*1024; +const UINT Apple2eRomSize = Apple2RomSize+CxRomSize; +//const UINT Pravets82RomSize = 12*1024; +//const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize; + void MemInitialize() { - // Init the I/O handlers - InitIoHandlers(); - - const UINT CxRomSize = 4*1024; - const UINT Apple2RomSize = 12*1024; - const UINT Apple2eRomSize = Apple2RomSize+CxRomSize; - //const UINT Pravets82RomSize = 12*1024; - //const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize; - // ALLOCATE MEMORY FOR THE APPLE MEMORY IMAGE AND ASSOCIATED DATA STRUCTURES memaux = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); memmain = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); @@ -1149,12 +1148,22 @@ void MemInitialize() #ifdef RAMWORKS // allocate memory for RAMWorks III - up to 8MB - RWpages[0] = memaux; + g_uActiveBank = 0; + RWpages[g_uActiveBank] = memaux; + UINT i = 1; while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE))) i++; #endif + MemInitializeROM(); + MemInitializeCustomF8ROM(); + MemInitializeIO(); + MemReset(); +} + +void MemInitializeROM(void) +{ // READ THE APPLE FIRMWARE ROMS INTO THE ROM IMAGE UINT ROM_SIZE = 0; HRSRC hResInfo = NULL; @@ -1211,8 +1220,6 @@ void MemInitialize() if (pData == NULL) return; - // - memset(pCxRomInternal,0,CxRomSize); memset(pCxRomPeripheral,0,CxRomSize); @@ -1224,17 +1231,23 @@ void MemInitialize() } _ASSERT(ROM_SIZE == Apple2RomSize); - memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF + memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF +} +void MemInitializeCustomF8ROM(void) +{ const UINT F8RomSize = 0x800; if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) { + BYTE OldRom[Apple2RomSize]; // NB. 12KB on stack + memcpy(OldRom, memrom, Apple2RomSize); + SetFilePointer(g_hCustomRomF8, 0, NULL, FILE_BEGIN); DWORD uNumBytesRead; BOOL bRes = ReadFile(g_hCustomRomF8, memrom+Apple2RomSize-F8RomSize, F8RomSize, &uNumBytesRead, NULL); if (uNumBytesRead != F8RomSize) { - memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF + memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF bRes = FALSE; } @@ -1249,15 +1262,27 @@ void MemInitialize() if (sg_PropertySheet.GetTheFreezesF8Rom() && IS_APPLE2) { - hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_FREEZES_F8_ROM), "ROM"); + HGLOBAL hResData = NULL; + BYTE* pData = NULL; + + HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_FREEZES_F8_ROM), "ROM"); if (hResInfo && (SizeofResource(NULL, hResInfo) == 0x800) && (hResData = LoadResource(NULL, hResInfo)) && (pData = (BYTE*) LockResource(hResData))) { memcpy(memrom+Apple2RomSize-F8RomSize, pData, F8RomSize); } } +} - // +// Called by: +// . MemInitialize() +// . Snapshot_LoadState_v2() +// +// Since called by LoadState(), then this must not init any cards +// - it should only init the card I/O hooks +void MemInitializeIO(void) +{ + InitIoHandlers(); const UINT uSlot = 0; RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL); @@ -1295,11 +1320,12 @@ void MemInitialize() { ConfigureSoftcard(pCxRomPeripheral, 5); // $C500 : Z80 card } + else + if (g_Slot5 == CT_SAM) + ConfigureSAM(pCxRomPeripheral, 5); // $C500 : Z80 card DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w - - MemReset(); } inline DWORD getRandomTime() @@ -1312,7 +1338,8 @@ inline DWORD getRandomTime() // Called by: // . MemInitialize() // . ResetMachineState() eg. Power-cycle ('Apple-Go' button) -// . Snapshot_LoadState() +// . Snapshot_LoadState_v1() +// . Snapshot_LoadState_v2() void MemReset() { // INITIALIZE THE PAGING TABLES @@ -1321,9 +1348,16 @@ void MemReset() // INITIALIZE THE RAM IMAGES ZeroMemory(memaux ,0x10000); - ZeroMemory(memmain,0x10000); + // Init the I/O ROM vars + IO_SELECT = 0; + IO_SELECT_InternalROM = 0; + g_eExpansionRomType = eExpRomNull; + g_uPeripheralRomSlot = 0; + + // + int iByte; // Memory is pseudo-initialized across various models of Apple ][ //e //c @@ -1394,14 +1428,14 @@ void MemReset() break; case MIP_RANDOM: - unsigned char random[ 256 + 4 ]; + unsigned char random[ 256 ]; for( iByte = 0x0000; iByte < 0xC000; iByte += 256 ) { for( int i = 0; i < 256; i++ ) { clock = getRandomTime(); - random[ i+0 ] ^= (clock >> 0) & 0xFF; - random[ i+1 ] ^= (clock >> 11) & 0xFF; + random[ (i+0) & 0xFF ] ^= (clock >> 0) & 0xFF; + random[ (i+1) & 0xFF ] ^= (clock >> 11) & 0xFF; } memcpy( &memmain[ iByte ], random, 256 ); @@ -1434,7 +1468,7 @@ void MemReset() // - "BeachParty-PoacherWars-DaytonDinger-BombsAway.dsk" // - "Dung Beetles, Ms. PacMan, Pooyan, Star Cruiser, Star Thief, Invas. Force.dsk" memmain[ 0x620B ] = 0x0; - + // https://github.com/AppleWin/AppleWin/issues/222 // MIP_PAGE_ADDRESS_LOW // "Copy II+ v5.0.dsk" @@ -1455,23 +1489,7 @@ void MemReset() CpuInitialize(); //Sets Caps Lock = false (Pravets 8A/C only) - z80_reset(); -} - -//=========================================================================== - -// Call by: -// . Soft-reset (Ctrl+Reset) -// . Snapshot_LoadState() -void MemResetPaging() -{ - ResetPaging(0); // Initialize=0 - if (g_Apple2Type == A2TYPE_PRAVETS8A) - { - P8CAPS_ON = false; - TapeWrite (0, 0, 0, 0 ,0); - FrameRefreshStatus(DRAW_LEDS); - } + z80_reset(); // NB. Also called above in CpuInitialize() } //=========================================================================== @@ -1592,7 +1610,8 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE case 0x73: // Ramworks III set aux page number if ((value < g_uMaxExPages) && RWpages[value]) { - memaux = RWpages[value]; + g_uActiveBank = value; + memaux = RWpages[g_uActiveBank]; UpdatePaging(0); // Initialize=0 } break; @@ -1670,34 +1689,218 @@ LPVOID MemGetSlotParameters(UINT uSlot) // . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode. // . This will work correctly. -DWORD MemGetSnapshot(SS_BaseMemory* pSS) +void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux) { - pSS->dwMemMode = memmode; - pSS->bLastWriteRam = lastwriteram; + SetMemMode(MemMode); + lastwriteram = LastWriteRam; - for(DWORD dwOffset = 0x0000; dwOffset < 0x10000; dwOffset+=0x100) - { - memcpy(pSS->nMemMain+dwOffset, MemGetMainPtr((WORD)dwOffset), 0x100); - memcpy(pSS->nMemAux+dwOffset, MemGetAuxPtr((WORD)dwOffset), 0x100); - } - - return 0; -} - -DWORD MemSetSnapshot(SS_BaseMemory* pSS) -{ - SetMemMode(pSS->dwMemMode); - lastwriteram = pSS->bLastWriteRam; - - memcpy(memmain, pSS->nMemMain, nMemMainSize); - memcpy(memaux, pSS->nMemAux, nMemAuxSize); + memcpy(memmain, pMemMain, nMemMainSize); + memcpy(memaux, pMemAux, nMemAuxSize); memset(memdirty, 0, 0x100); // modechanging = 0; - + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v1() UpdatePaging(1); // Initialize=1 - - return 0; +} + +// + +#define UNIT_AUXSLOT_VER 1 + +#define SS_YAML_KEY_MEMORYMODE "Memory Mode" +#define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write" +#define SS_YAML_KEY_IOSELECT "IO_SELECT" +#define SS_YAML_KEY_IOSELECT_INT "IO_SELECT_InternalROM" +#define SS_YAML_KEY_EXPANSIONROMTYPE "Expansion ROM Type" +#define SS_YAML_KEY_PERIPHERALROMSLOT "Peripheral ROM Slot" + +#define SS_YAML_VALUE_CARD_80COL "80 Column" +#define SS_YAML_VALUE_CARD_EXTENDED80COL "Extended 80 Column" +#define SS_YAML_VALUE_CARD_RAMWORKSIII "RamWorksIII" + +#define SS_YAML_KEY_NUMAUXBANKS "Num Aux Banks" +#define SS_YAML_KEY_ACTIVEAUXBANK "Active Aux Bank" + +static std::string MemGetSnapshotStructName(void) +{ + static const std::string name("Memory"); + return name; +} + +std::string MemGetSnapshotUnitAuxSlotName(void) +{ + static const std::string name("Auxiliary Slot"); + return name; +} + +static std::string MemGetSnapshotMainMemStructName(void) +{ + static const std::string name("Main Memory"); + return name; +} + +static std::string MemGetSnapshotAuxMemStructName(void) +{ + static const std::string name("Auxiliary Memory Bank"); + return name; +} + +static void MemSaveSnapshotMemory(YamlSaveHelper& yamlSaveHelper, bool bIsMainMem, UINT bank=0) +{ + LPBYTE pMemBase = MemGetBankPtr(bank); + + if (bIsMainMem) + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotMainMemStructName().c_str()); + yamlSaveHelper.SaveMemory(pMemBase, 64*1024); + } + else + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s%02X:\n", MemGetSnapshotAuxMemStructName().c_str(), bank-1); + yamlSaveHelper.SaveMemory(pMemBase, 64*1024); + } +} + +void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + // Scope so that "Memory" & "Main Memory" are at same indent level + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, memmode); + yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, lastwriteram ? 1 : 0); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT, IO_SELECT); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT_INT, IO_SELECT_InternalROM); + yamlSaveHelper.SaveUint(SS_YAML_KEY_EXPANSIONROMTYPE, (UINT) g_eExpansionRomType); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PERIPHERALROMSLOT, g_uPeripheralRomSlot); + } + + MemSaveSnapshotMemory(yamlSaveHelper, true); +} + +bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(MemGetSnapshotStructName())) + return false; + + SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ); + lastwriteram = yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE; + IO_SELECT = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT); + IO_SELECT_InternalROM = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT_INT); + g_eExpansionRomType = (eExpansionRomType) yamlLoadHelper.LoadUint(SS_YAML_KEY_EXPANSIONROMTYPE); + g_uPeripheralRomSlot = yamlLoadHelper.LoadUint(SS_YAML_KEY_PERIPHERALROMSLOT); + + yamlLoadHelper.PopMap(); + + // + + if (!yamlLoadHelper.GetSubMap( MemGetSnapshotMainMemStructName() )) + throw std::string("Card: Expected key: ") + MemGetSnapshotMainMemStructName(); + + yamlLoadHelper.LoadMemory(memmain, _6502_MEM_END+1); + memset(memdirty, 0, 0x100); + + yamlLoadHelper.PopMap(); + + // + + modechanging = 0; + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() + UpdatePaging(1); // Initialize=1 (Still needed, even with call to MemUpdatePaging() - why?) + + return true; +} + +void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper) +{ + if (IS_APPLE2) + { + return; // No Aux slot for AppleII + } + + if (IS_APPLE2C) + { + _ASSERT(g_uMaxExPages == 1); + } + + yamlSaveHelper.UnitHdr(MemGetSnapshotUnitAuxSlotName(), UNIT_AUXSLOT_VER); + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + std::string card = g_uMaxExPages == 0 ? SS_YAML_VALUE_CARD_80COL : // todo: support empty slot + g_uMaxExPages == 1 ? SS_YAML_VALUE_CARD_EXTENDED80COL : + SS_YAML_VALUE_CARD_RAMWORKSIII; + yamlSaveHelper.SaveString(SS_YAML_KEY_CARD, card.c_str()); + yamlSaveHelper.Save("%s: %02X # [0,1..7F] 0=no aux mem, 1=128K system, etc\n", SS_YAML_KEY_NUMAUXBANKS, g_uMaxExPages); + yamlSaveHelper.Save("%s: %02X # [ 0..7E] 0=memaux\n", SS_YAML_KEY_ACTIVEAUXBANK, g_uActiveBank); + + for(UINT uBank = 1; uBank <= g_uMaxExPages; uBank++) + { + MemSaveSnapshotMemory(yamlSaveHelper, false, uBank); + } +} + +bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version) +{ + if (version != UNIT_AUXSLOT_VER) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Version mismatch"); + + // "State" + UINT numAuxBanks = yamlLoadHelper.LoadUint(SS_YAML_KEY_NUMAUXBANKS); + UINT activeAuxBank = yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVEAUXBANK); + + std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD); + if (card == SS_YAML_VALUE_CARD_80COL) + { + if (numAuxBanks != 0 || activeAuxBank != 0) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); + } + else if (card == SS_YAML_VALUE_CARD_EXTENDED80COL) + { + if (numAuxBanks != 1 || activeAuxBank != 0) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); + } + else if (card == SS_YAML_VALUE_CARD_RAMWORKSIII) + { + if (numAuxBanks < 2 || numAuxBanks > 0x7F || (activeAuxBank+1) > numAuxBanks) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); + } + else + { + // todo: support empty slot + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Unknown card: " + card); + } + + g_uMaxExPages = numAuxBanks; + g_uActiveBank = activeAuxBank; + + // + + for(UINT uBank = 1; uBank <= g_uMaxExPages; uBank++) + { + LPBYTE pBank = MemGetBankPtr(uBank); + if (!pBank) + { + pBank = RWpages[uBank-1] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); + if (!pBank) + throw std::string("Card: mem alloc failed"); + } + + // "Auxiliary Memory Bankxx" + char szBank[3]; + sprintf(szBank, "%02X", uBank-1); + std::string auxMemName = MemGetSnapshotAuxMemStructName() + szBank; + + if (!yamlLoadHelper.GetSubMap(auxMemName)) + throw std::string("Memory: Missing map name: " + auxMemName); + + yamlLoadHelper.LoadMemory(pBank, _6502_MEM_END+1); + + yamlLoadHelper.PopMap(); + } + + memaux = RWpages[g_uActiveBank]; + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() + + return true; } diff --git a/source/Memory.h b/source/Memory.h index 207cd1b1..3a104755 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -32,6 +32,7 @@ extern LPBYTE mem; extern LPBYTE memdirty; #ifdef RAMWORKS +const UINT kMaxExMemoryBanks = 127; // 127 * aux mem(64K) + main mem(64K) = 8MB extern UINT g_uMaxExPages; // user requested ram pages (from cmd line) #endif @@ -44,14 +45,21 @@ LPBYTE MemGetMainPtr(const WORD); LPBYTE MemGetBankPtr(const UINT nBank); LPBYTE MemGetCxRomPeripheral(); void MemInitialize (); +void MemInitializeROM(void); +void MemInitializeCustomF8ROM(void); +void MemInitializeIO(void); BYTE MemReadFloatingBus(const ULONG uExecutedCycles); BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles); void MemReset (); void MemResetPaging (); void MemUpdatePaging(BOOL initialize); LPVOID MemGetSlotParameters (UINT uSlot); -DWORD MemGetSnapshot(SS_BaseMemory* pSS); -DWORD MemSetSnapshot(SS_BaseMemory* pSS); +void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux); +std::string MemGetSnapshotUnitAuxSlotName(void); +void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); +void MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper); +bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version); BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 590c7870..0143f8e9 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -77,12 +77,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" +#include "SaveState_Structs_v1.h" + #include "AppleWin.h" #include "CPU.h" #include "Log.h" #include "Memory.h" #include "Mockingboard.h" #include "SoundCore.h" +#include "YamlHelper.h" #include "AY8910.h" #include "SSI263Phonemes.h" @@ -114,14 +117,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define Phasor_SY6522A_Offset (1<SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin - pMB->SpeechChip.DurationPhonome = nValue; + pMB->SpeechChip.DurationPhoneme = nValue; g_nSSI263Device = nDevice; @@ -632,7 +636,7 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue) if(g_fh) fprintf(g_fh, "CTRL = %d, ART = 0x%02X, AMP=0x%02X\n", nValue>>7, (nValue&ARTICULATION_MASK)>>4, nValue&LITUDE_MASK); #endif if((pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK)) // H->L - pMB->SpeechChip.CurrentMode = pMB->SpeechChip.DurationPhonome & DURATION_MODE_MASK; + pMB->SpeechChip.CurrentMode = pMB->SpeechChip.DurationPhoneme & DURATION_MODE_MASK; pMB->SpeechChip.CtrlArtAmp = nValue; break; case SSI_FILFREQ: @@ -826,7 +830,7 @@ static void MB_Update() double fTicksSecs = (double)GetTickCount() / 1000.0; sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg); - if (g_fh) fprintf(g_fh, szDbg); + if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; } @@ -839,7 +843,7 @@ static void MB_Update() double fTicksSecs = (double)GetTickCount() / 1000.0; sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg); - if (g_fh) fprintf(g_fh, szDbg); + if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; } @@ -1002,11 +1006,22 @@ static void SSI263_Play(unsigned int nPhoneme) #if 1 HRESULT hr; - if(g_nCurrentActivePhoneme >= 0) { - // A write to DURPHON before previous phoneme has completed - g_bStopPhoneme = true; - hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->Stop(); + int nCurrPhoneme = g_nCurrentActivePhoneme; // local copy in case SSI263Thread sets it to -1 + if (nCurrPhoneme >= 0) + { + // A write to DURPHON before previous phoneme has completed + g_bStopPhoneme = true; + hr = SSI263Voice[nCurrPhoneme].lpDSBvoice->Stop(); + + // Busy-wait until ACK from SSI263Thread + // . required to avoid data-race + while ( g_bStopPhoneme && // wait for SSI263Thread to ACK the lpDSBVoice->Stop() + g_nCurrentActivePhoneme >= 0) // wait for SSI263Thread to get end of sample event + ; + + g_bStopPhoneme = false; + } } g_nCurrentActivePhoneme = nPhoneme; @@ -1371,7 +1386,8 @@ void MB_Initialize() // NB. Called when /g_fCurrentCLK6502/ changes void MB_Reinitialize() { - AY8910_InitClock((int)g_fCurrentCLK6502); + AY8910_InitClock((int)g_fCurrentCLK6502); // todo: account for g_PhasorClockScaleFactor? + // NB. Other calls to AY8910_InitClock() use the constant CLK_6502 } //----------------------------------------------------------------------------- @@ -1403,9 +1419,10 @@ static void ResetState() //g_bMBAvailable = false; - //g_SoundcardType = CT_Empty; - //g_bPhasorEnable = false; +// g_SoundcardType = CT_Empty; // Don't uncomment, else _ASSERT will fire in MB_Read() after an F2->MB_Reset() +// g_bPhasorEnable = false; g_nPhasorMode = 0; + g_PhasorClockScaleFactor = 1; } void MB_Reset() @@ -1553,9 +1570,9 @@ static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL if(g_nPhasorMode < 2) g_nPhasorMode = nAddr & 1; - double fCLK = (nAddr & 4) ? CLK_6502*2 : CLK_6502; + g_PhasorClockScaleFactor = (nAddr & 4) ? 2 : 1; - AY8910_InitClock((int)fCLK); + AY8910_InitClock((int)(CLK_6502 * g_PhasorClockScaleFactor)); return MemReadFloatingBus(nCyclesLeft); } @@ -1761,45 +1778,48 @@ void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax) //=========================================================================== -DWORD MB_GetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot) +// Called by debugger - Debugger_Display.cpp +void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot) { - pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2); - pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); + pSS->Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_MOCKINGBOARD_v1); + pSS->Hdr.UnitHdr.hdr.v2.Type = UT_Card; + pSS->Hdr.UnitHdr.hdr.v2.Version = 1; - pSS->Hdr.dwSlot = dwSlot; - pSS->Hdr.dwType = CT_MockingboardC; + pSS->Hdr.Slot = dwSlot; + pSS->Hdr.Type = CT_MockingboardC; UINT nMbCardNum = dwSlot - SLOT4; UINT nDeviceNum = nMbCardNum*2; SY6522_AY8910* pMB = &g_MB[nDeviceNum]; - for(UINT i=0; iUnit[i].RegsSY6522, &pMB->sy6522, sizeof(SY6522)); memcpy(&pSS->Unit[i].RegsAY8910, AY8910_GetRegsPtr(nDeviceNum), 16); memcpy(&pSS->Unit[i].RegsSSI263, &pMB->SpeechChip, sizeof(SSI263A)); pSS->Unit[i].nAYCurrentRegister = pMB->nAYCurrentRegister; + pSS->Unit[i].bTimer1IrqPending = false; + pSS->Unit[i].bTimer2IrqPending = false; + pSS->Unit[i].bSpeechIrqPending = false; nDeviceNum++; pMB++; } - - return 0; } -DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/) +int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD /*dwSlot*/) { - if(pSS->Hdr.UnitHdr.dwVersion != MAKE_VERSION(1,0,0,0)) + if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion != MAKE_VERSION(1,0,0,0)) return -1; - UINT nMbCardNum = pSS->Hdr.dwSlot - SLOT4; + UINT nMbCardNum = pSS->Hdr.Slot - SLOT4; UINT nDeviceNum = nMbCardNum*2; SY6522_AY8910* pMB = &g_MB[nDeviceNum]; g_nSSI263Device = 0; g_nCurrentActivePhoneme = -1; - for(UINT i=0; isy6522, &pSS->Unit[i].RegsSY6522, sizeof(SY6522)); memcpy(AY8910_GetRegsPtr(nDeviceNum), &pSS->Unit[i].RegsAY8910, 16); @@ -1814,7 +1834,7 @@ DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/) // FIX THIS: // . Speech chip could be Votrax instead // . Is this IRQ compatible with Phasor? - if(pMB->SpeechChip.DurationPhonome) + if(pMB->SpeechChip.DurationPhoneme) { g_nSSI263Device = nDeviceNum; @@ -1832,3 +1852,357 @@ DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/) return 0; } + +//=========================================================================== + +static UINT DoWriteFile(const HANDLE hFile, const void* const pData, const UINT Length) +{ + DWORD dwBytesWritten; + BOOL bRes = WriteFile( hFile, + pData, + Length, + &dwBytesWritten, + NULL); + + if(!bRes || (dwBytesWritten != Length)) + { + //dwError = GetLastError(); + throw std::string("Card: save error"); + } + + return dwBytesWritten; +} + +static UINT DoReadFile(const HANDLE hFile, void* const pData, const UINT Length) +{ + DWORD dwBytesRead; + BOOL bRes = ReadFile( hFile, + pData, + Length, + &dwBytesRead, + NULL); + + if (dwBytesRead != Length) + throw std::string("Card: file corrupt"); + + return dwBytesRead; +} + +//=========================================================================== + +const UINT NUM_MB_UNITS = 2; +const UINT NUM_PHASOR_UNITS = 2; + +#define SS_YAML_KEY_MB_UNIT "Unit" +#define SS_YAML_KEY_SY6522 "SY6522" +#define SS_YAML_KEY_SY6522_REG_ORB "ORB" +#define SS_YAML_KEY_SY6522_REG_ORA "ORA" +#define SS_YAML_KEY_SY6522_REG_DDRB "DDRB" +#define SS_YAML_KEY_SY6522_REG_DDRA "DDRA" +#define SS_YAML_KEY_SY6522_REG_T1_COUNTER "Timer1 Counter" +#define SS_YAML_KEY_SY6522_REG_T1_LATCH "Timer1 Latch" +#define SS_YAML_KEY_SY6522_REG_T2_COUNTER "Timer2 Counter" +#define SS_YAML_KEY_SY6522_REG_T2_LATCH "Timer2 Latch" +#define SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT "Serial Shift" +#define SS_YAML_KEY_SY6522_REG_ACR "ACR" +#define SS_YAML_KEY_SY6522_REG_PCR "PCR" +#define SS_YAML_KEY_SY6522_REG_IFR "IFR" +#define SS_YAML_KEY_SY6522_REG_IER "IER" +#define SS_YAML_KEY_SSI263 "SSI263" +#define SS_YAML_KEY_SSI263_REG_DUR_PHON "Duration / Phoneme" +#define SS_YAML_KEY_SSI263_REG_INF "Inflection" +#define SS_YAML_KEY_SSI263_REG_RATE_INF "Rate / Inflection" +#define SS_YAML_KEY_SSI263_REG_CTRL_ART_AMP "Control / Articulation / Amplitude" +#define SS_YAML_KEY_SSI263_REG_FILTER_FREQ "Filter Frequency" +#define SS_YAML_KEY_SSI263_REG_CURRENT_MODE "Current Mode" +#define SS_YAML_KEY_AY_CURR_REG "AY Current Register" +#define SS_YAML_KEY_TIMER1_IRQ "Timer1 IRQ Pending" +#define SS_YAML_KEY_TIMER2_IRQ "Timer2 IRQ Pending" +#define SS_YAML_KEY_SPEECH_IRQ "Speech IRQ Pending" + +#define SS_YAML_KEY_PHASOR_UNIT "Unit" +#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor" +#define SS_YAML_KEY_PHASOR_MODE "Mode" + +std::string MB_GetSnapshotCardName(void) +{ + static const std::string name("Mockingboard C"); + return name; +} + +std::string Phasor_GetSnapshotCardName(void) +{ + static const std::string name("Phasor"); + return name; +} + +static void SaveSnapshotSY6522(YamlSaveHelper& yamlSaveHelper, SY6522& sy6522) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", SS_YAML_KEY_SY6522); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ORB, sy6522.ORB); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ORA, sy6522.ORA); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_DDRB, sy6522.DDRB); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_DDRA, sy6522.DDRA); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_COUNTER, sy6522.TIMER1_COUNTER.w); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_LATCH, sy6522.TIMER1_LATCH.w); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_COUNTER, sy6522.TIMER2_COUNTER.w); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_LATCH, sy6522.TIMER2_LATCH.w); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT, sy6522.SERIAL_SHIFT); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ACR, sy6522.ACR); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_PCR, sy6522.PCR); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_IFR, sy6522.IFR); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_IER, sy6522.IER); + // NB. No need to write ORA_NO_HS, since same data as ORA, just without handshake +} + +static void SaveSnapshotSSI263(YamlSaveHelper& yamlSaveHelper, SSI263A& ssi263) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", SS_YAML_KEY_SSI263); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_DUR_PHON, ssi263.DurationPhoneme); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_INF, ssi263.Inflection); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_RATE_INF, ssi263.RateInflection); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_CTRL_ART_AMP, ssi263.CtrlArtAmp); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_FILTER_FREQ, ssi263.FilterFreq); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_CURRENT_MODE, ssi263.CurrentMode); +} + +void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) +{ + const UINT nMbCardNum = uSlot - SLOT4; + UINT nDeviceNum = nMbCardNum*2; + SY6522_AY8910* pMB = &g_MB[nDeviceNum]; + + YamlSaveHelper::Slot slot(yamlSaveHelper, MB_GetSnapshotCardName(), uSlot, 1); // fixme: object should be just 1 Mockingboard card & it will know its slot + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + for(UINT i=0; isy6522); + AY8910_SaveSnapshot(yamlSaveHelper, nDeviceNum, std::string("")); + SaveSnapshotSSI263(yamlSaveHelper, pMB->SpeechChip); + + yamlSaveHelper.SaveHexUint4(SS_YAML_KEY_AY_CURR_REG, pMB->nAYCurrentRegister); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER1_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER2_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_SPEECH_IRQ, "false"); + + nDeviceNum++; + pMB++; + } +} + +static void LoadSnapshotSY6522(YamlLoadHelper& yamlLoadHelper, SY6522& sy6522) +{ + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SY6522)) + throw std::string("Card: Expected key: ") + std::string(SS_YAML_KEY_SY6522); + + sy6522.ORB = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_ORB); + sy6522.ORA = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_ORA); + sy6522.DDRB = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_DDRB); + sy6522.DDRA = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_DDRA); + sy6522.TIMER1_COUNTER.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T1_COUNTER); + sy6522.TIMER1_LATCH.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T1_LATCH); + sy6522.TIMER2_COUNTER.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T2_COUNTER); + sy6522.TIMER2_LATCH.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T2_LATCH); + sy6522.SERIAL_SHIFT = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT); + sy6522.ACR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_ACR); + sy6522.PCR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_PCR); + sy6522.IFR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_IFR); + sy6522.IER = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_IER); + sy6522.ORA_NO_HS = 0; // Not saved + + yamlLoadHelper.PopMap(); +} + +static void LoadSnapshotSSI263(YamlLoadHelper& yamlLoadHelper, SSI263A& ssi263) +{ + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SSI263)) + throw std::string("Card: Expected key: ") + std::string(SS_YAML_KEY_SSI263); + + ssi263.DurationPhoneme = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_DUR_PHON); + ssi263.Inflection = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_INF); + ssi263.RateInflection = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_RATE_INF); + ssi263.CtrlArtAmp = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_CTRL_ART_AMP); + ssi263.FilterFreq = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_FILTER_FREQ); + ssi263.CurrentMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_CURRENT_MODE); + + yamlLoadHelper.PopMap(); +} + +bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 4 && slot != 5) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + AY8910UpdateSetCycles(); + + const UINT nMbCardNum = slot - SLOT4; + UINT nDeviceNum = nMbCardNum*2; + SY6522_AY8910* pMB = &g_MB[nDeviceNum]; + + g_nSSI263Device = 0; + g_nCurrentActivePhoneme = -1; + + for(UINT i=0; isy6522); + AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum, std::string("")); + LoadSnapshotSSI263(yamlLoadHelper, pMB->SpeechChip); + + pMB->nAYCurrentRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_AY_CURR_REG); + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER1_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_SPEECH_IRQ); // Consume + + yamlLoadHelper.PopMap(); + + // + + StartTimer(pMB); // Attempt to start timer + + // Crude - currently only support a single speech chip + // FIX THIS: + // . Speech chip could be Votrax instead + // . Is this IRQ compatible with Phasor? + if(pMB->SpeechChip.DurationPhoneme) + { + g_nSSI263Device = nDeviceNum; + + if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL)) + { + pMB->sy6522.IFR |= IxR_PERIPHERAL; + UpdateIFR(pMB); + pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin + } + } + + nDeviceNum++; + pMB++; + } + + AY8910_InitClock((int)CLK_6502); + + // Setup in MB_InitializeIO() -> MB_SetSoundcardType() + g_SoundcardType = CT_Empty; + g_bPhasorEnable = false; + + return true; +} + +void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) +{ + if (uSlot != 4) + throw std::string("Card: Phasor only supported in slot-4"); + + UINT nDeviceNum = 0; + SY6522_AY8910* pMB = &g_MB[0]; // fixme: Phasor uses MB's slot4(2x6522), slot4(2xSSI263), but slot4+5(4xAY8910) + + YamlSaveHelper::Slot slot(yamlSaveHelper, Phasor_GetSnapshotCardName(), uSlot, 1); // fixme: object should be just 1 Mockingboard card & it will know its slot + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR, g_PhasorClockScaleFactor); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_MODE, g_nPhasorMode); + + for(UINT i=0; isy6522); + AY8910_SaveSnapshot(yamlSaveHelper, nDeviceNum+0, std::string("-A")); + AY8910_SaveSnapshot(yamlSaveHelper, nDeviceNum+1, std::string("-B")); + SaveSnapshotSSI263(yamlSaveHelper, pMB->SpeechChip); + + yamlSaveHelper.SaveHexUint4(SS_YAML_KEY_AY_CURR_REG, pMB->nAYCurrentRegister); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER1_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER2_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_SPEECH_IRQ, "false"); + + nDeviceNum += 2; + pMB++; + } +} + +bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 4) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + g_PhasorClockScaleFactor = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR); + g_nPhasorMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_MODE); + + AY8910UpdateSetCycles(); + + UINT nDeviceNum = 0; + SY6522_AY8910* pMB = &g_MB[0]; + + g_nSSI263Device = 0; + g_nCurrentActivePhoneme = -1; + + for(UINT i=0; isy6522); + AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum+0, std::string("-A")); + AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum+1, std::string("-B")); + LoadSnapshotSSI263(yamlLoadHelper, pMB->SpeechChip); + + pMB->nAYCurrentRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_AY_CURR_REG); + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER1_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_SPEECH_IRQ); // Consume + + yamlLoadHelper.PopMap(); + + // + + StartTimer(pMB); // Attempt to start timer + + // Crude - currently only support a single speech chip + // FIX THIS: + // . Speech chip could be Votrax instead + // . Is this IRQ compatible with Phasor? + if(pMB->SpeechChip.DurationPhoneme) + { + g_nSSI263Device = nDeviceNum; + + if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL)) + { + pMB->sy6522.IFR |= IxR_PERIPHERAL; + UpdateIFR(pMB); + pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin + } + } + + nDeviceNum += 2; + pMB++; + } + + AY8910_InitClock((int)(CLK_6502 * g_PhasorClockScaleFactor)); + + // Setup in MB_InitializeIO() -> MB_SetSoundcardType() + g_SoundcardType = CT_Empty; + g_bPhasorEnable = false; + + return true; +} diff --git a/source/Mockingboard.h b/source/Mockingboard.h index edd337b8..901a9e41 100644 --- a/source/Mockingboard.h +++ b/source/Mockingboard.h @@ -22,5 +22,13 @@ double MB_GetFramePeriod(); bool MB_IsActive(); DWORD MB_GetVolume(); void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax); -DWORD MB_GetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot); -DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot); + +void MB_GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot); // For debugger +int MB_SetSnapshot_v1(const struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot); +std::string MB_GetSnapshotCardName(void); +void MB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); +bool MB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + +std::string Phasor_GetSnapshotCardName(void); +void Phasor_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); +bool Phasor_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); diff --git a/source/MouseInterface.cpp b/source/MouseInterface.cpp index 0805e3ff..34b25788 100644 --- a/source/MouseInterface.cpp +++ b/source/MouseInterface.cpp @@ -41,7 +41,7 @@ Etc. #include "stdafx.h" -#include "Structs.h" +#include "SaveState_Structs_common.h" #include "Common.h" #include "CPU.h" @@ -50,6 +50,7 @@ Etc. #include "Memory.h" #include "MouseInterface.h" #include "SoundCore.h" // SAFE_RELEASE() +#include "YamlHelper.h" #include "..\resource\resource.h" @@ -210,7 +211,7 @@ void CMouseInterface::Reset() m_iMinY = 0; m_iMaxY = 1023; - m_bButtons[0] = m_bButtons[1] = FALSE; + m_bButtons[0] = m_bButtons[1] = false; // @@ -447,15 +448,13 @@ void CMouseInterface::OnMouseEvent(bool bEventVBL) if ( !( m_byMode & MODE_MOUSE_ON ) ) // Mouse Off return; - BOOL bBtn0 = m_bButtons[0]; - BOOL bBtn1 = m_bButtons[1]; if ( m_nX != m_iX || m_nY != m_iY ) { byState |= STAT_INT_MOVEMENT|STAT_MOVEMENT_SINCE_READMOUSE; // X/Y moved since last READMOUSE | Movement interrupt m_byState |= STAT_MOVEMENT_SINCE_READMOUSE; // [TC] Used by CopyII+9.1 and ProTERM3.1 } - if ( m_bBtn0 != bBtn0 || m_bBtn1 != bBtn1 ) + if ( m_bBtn0 != m_bButtons[0] || m_bBtn1 != m_bButtons[1] ) byState |= STAT_INT_BUTTON; // Button 0/1 interrupt if ( bEventVBL ) byState |= STAT_INT_VBL; @@ -495,8 +494,8 @@ void CMouseInterface::Clear() m_byState = 0; m_nX = 0; m_nY = 0; - m_bBtn0 = 0; - m_bBtn1 = 0; + m_bBtn0 = false; + m_bBtn1 = false; SetPositionAbs( 0, 0 ); // CpuIrqDeassert(IS_MOUSE); @@ -594,10 +593,168 @@ void CMouseInterface::SetPositionRel(long dX, long dY, int* pOutOfBoundsX, int* void CMouseInterface::SetButton(eBUTTON Button, eBUTTONSTATE State) { - m_bButtons[Button]= (State == BUTTON_DOWN) ? TRUE : FALSE; + m_bButtons[Button] = (State == BUTTON_DOWN); OnMouseEvent(); } +#define SS_YAML_VALUE_CARD_MOUSE "Mouse Card" + +#define SS_YAML_KEY_MC6821 "MC6821" +#define SS_YAML_KEY_PRA "PRA" +#define SS_YAML_KEY_DDRA "DDRA" +#define SS_YAML_KEY_CRA "CRA" +#define SS_YAML_KEY_PRB "PRB" +#define SS_YAML_KEY_DDRB "DDRB" +#define SS_YAML_KEY_CRB "CRB" +#define SS_YAML_KEY_IA "IA" +#define SS_YAML_KEY_IB "IB" + +#define SS_YAML_KEY_DATALEN "DataLen" +#define SS_YAML_KEY_MODE "Mode" +#define SS_YAML_KEY_6821B "6821B" +#define SS_YAML_KEY_6821A "6821A" +#define SS_YAML_KEY_BUFF "Buffer" +#define SS_YAML_KEY_BUFFPOS "Buffer Position" +#define SS_YAML_KEY_MOUSESTATE "State" +#define SS_YAML_KEY_X "X" +#define SS_YAML_KEY_Y "Y" +#define SS_YAML_KEY_BTN0 "Btn0" +#define SS_YAML_KEY_BTN1 "Btn1" +#define SS_YAML_KEY_VBL "VBL" +#define SS_YAML_KEY_IX "iX" +#define SS_YAML_KEY_IMINX "iMinX" +#define SS_YAML_KEY_IMAXX "iMaxX" +#define SS_YAML_KEY_IY "iY" +#define SS_YAML_KEY_IMINY "iMinY" +#define SS_YAML_KEY_IMAXY "iMaxY" +#define SS_YAML_KEY_BUTTON0 "Button0" +#define SS_YAML_KEY_BUTTON1 "Button1" +#define SS_YAML_KEY_ENABLED "Enabled" + +std::string CMouseInterface::GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_MOUSE); + return name; +} + +void CMouseInterface::SaveSnapshotMC6821(YamlSaveHelper& yamlSaveHelper, std::string key) +{ + mc6821_t mc6821; + BYTE byIA; + BYTE byIB; + + m_6821.Get6821(mc6821, byIA, byIB); + + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", key.c_str()); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PRA, mc6821.pra); + yamlSaveHelper.SaveUint(SS_YAML_KEY_DDRA, mc6821.ddra); + yamlSaveHelper.SaveUint(SS_YAML_KEY_CRA, mc6821.cra); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PRB, mc6821.prb); + yamlSaveHelper.SaveUint(SS_YAML_KEY_DDRB, mc6821.ddrb); + yamlSaveHelper.SaveUint(SS_YAML_KEY_CRB, mc6821.crb); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IA, byIA); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IB, byIB); +} + +void CMouseInterface::SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) +{ + if (!m_bActive) + return; + + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_uSlot, 1); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + SaveSnapshotMC6821(yamlSaveHelper, SS_YAML_KEY_MC6821); + yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_DATALEN, m_nDataLen); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MODE, m_byMode); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_6821B, m_by6821B); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_6821A, m_by6821A); + + // New label + { + YamlSaveHelper::Label buffer(yamlSaveHelper, "%s:\n", SS_YAML_KEY_BUFF); + yamlSaveHelper.SaveMemory(m_byBuff, sizeof(m_byBuff)); + } + + yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_BUFFPOS, m_nBuffPos); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MOUSESTATE, m_byState); + yamlSaveHelper.SaveUint(SS_YAML_KEY_X, m_nX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_Y, m_nY); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BTN0, m_bBtn0); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BTN1, m_bBtn1); + yamlSaveHelper.SaveBool(SS_YAML_KEY_VBL, m_bVBL); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IX, m_iX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMINX, m_iMinX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMAXX, m_iMaxX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IY, m_iY); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMINY, m_iMinY); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMAXY, m_iMaxY); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BUTTON0, m_bButtons[0]); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BUTTON1, m_bButtons[1]); + yamlSaveHelper.SaveBool(SS_YAML_KEY_ENABLED, m_bEnabled); +} + +void CMouseInterface::LoadSnapshotMC6821(YamlLoadHelper& yamlLoadHelper, std::string key) +{ + if (!yamlLoadHelper.GetSubMap(key)) + throw std::string("Card: Expected key: ") + key; + + mc6821_t mc6821; + mc6821.pra = yamlLoadHelper.LoadUint(SS_YAML_KEY_PRA); + mc6821.ddra = yamlLoadHelper.LoadUint(SS_YAML_KEY_DDRA); + mc6821.cra = yamlLoadHelper.LoadUint(SS_YAML_KEY_CRA); + mc6821.prb = yamlLoadHelper.LoadUint(SS_YAML_KEY_PRB); + mc6821.ddrb = yamlLoadHelper.LoadUint(SS_YAML_KEY_DDRB); + mc6821.crb = yamlLoadHelper.LoadUint(SS_YAML_KEY_CRB); + + BYTE byIA = yamlLoadHelper.LoadUint(SS_YAML_KEY_IA); + BYTE byIB = yamlLoadHelper.LoadUint(SS_YAML_KEY_IB); + + m_6821.Set6821(mc6821, byIA, byIB); + + yamlLoadHelper.PopMap(); +} + +bool CMouseInterface::LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 4) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + LoadSnapshotMC6821(yamlLoadHelper, SS_YAML_KEY_MC6821); + + m_nDataLen = yamlLoadHelper.LoadUint(SS_YAML_KEY_DATALEN); + m_byMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MODE); + m_by6821B = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821B); + m_by6821A = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821A); + + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_BUFF)) + throw std::string("Card: Expected key: "SS_YAML_KEY_BUFF); + yamlLoadHelper.LoadMemory(m_byBuff, sizeof(m_byBuff)); + yamlLoadHelper.PopMap(); + + m_nBuffPos = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUFFPOS); + m_byState = yamlLoadHelper.LoadUint(SS_YAML_KEY_MOUSESTATE); + m_nX = yamlLoadHelper.LoadInt(SS_YAML_KEY_X); + m_nY = yamlLoadHelper.LoadInt(SS_YAML_KEY_Y); + m_bBtn0 = yamlLoadHelper.LoadBool(SS_YAML_KEY_BTN0); + m_bBtn1 = yamlLoadHelper.LoadBool(SS_YAML_KEY_BTN1); + m_bVBL = yamlLoadHelper.LoadBool(SS_YAML_KEY_VBL); + m_iX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IX); + m_iMinX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMINX); + m_iMaxX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMAXX); + m_iY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IY); + m_iMinY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMINY); + m_iMaxY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMAXY); + m_bButtons[0] = yamlLoadHelper.LoadBool(SS_YAML_KEY_BUTTON0); + m_bButtons[1] = yamlLoadHelper.LoadBool(SS_YAML_KEY_BUTTON1); + m_bEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_ENABLED); // MemInitializeIO() calls Initialize() which sets true + + return true; +} + //============================================================================= // DirectInput interface //============================================================================= @@ -819,4 +976,4 @@ namespace DIMouse return S_OK; } -}; // namespace DIMouse \ No newline at end of file +}; // namespace DIMouse diff --git a/source/MouseInterface.h b/source/MouseInterface.h index 6c13a4f2..2b48f0f0 100644 --- a/source/MouseInterface.h +++ b/source/MouseInterface.h @@ -12,15 +12,14 @@ public: void Initialize(LPBYTE pCxRomPeripheral, UINT uSlot); void Uninitialize(); void Reset(); - void SetSlotRom(); static BYTE __stdcall IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft); static BYTE __stdcall IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft); void SetPositionRel(long dx, long dy, int* pOutOfBoundsX, int* pOutOfBoundsY); void SetButton(eBUTTON Button, eBUTTONSTATE State); bool IsActive() { return m_bActive; } - bool IsEnabled() { return m_bEnabled; } - bool IsActiveAndEnabled() { return IsActive() && IsEnabled(); } + bool IsEnabled() { return m_bEnabled; } // NB. m_bEnabled == true implies that m_bActive == true + bool IsActiveAndEnabled() { return IsActive() && IsEnabled(); } // todo: just use IsEnabled() void SetEnabled(bool bEnabled) { m_bEnabled = bEnabled; } void SetVBlank(bool bVBL); void GetXY(int& iX, int& iMinX, int& iMaxX, int& iY, int& iMinY, int& iMaxY) @@ -38,7 +37,12 @@ public: m_iY = iY; } + std::string GetSnapshotCardName(void); + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + protected: + void SetSlotRom(); void On6821_A(BYTE byData); void On6821_B(BYTE byData); void OnCommand(); @@ -55,6 +59,8 @@ protected: void SetClampX(int iMinX, int iMaxX); void SetClampY(int iMinY, int iMaxY); + void SaveSnapshotMC6821(class YamlSaveHelper& yamlSaveHelper, std::string key); + void LoadSnapshotMC6821(class YamlLoadHelper& yamlLoadHelper, std::string key); C6821 m_6821; @@ -69,8 +75,8 @@ protected: BYTE m_byState; int m_nX; int m_nY; - BOOL m_bBtn0; - BOOL m_bBtn1; + bool m_bBtn0; + bool m_bBtn1; bool m_bVBL; @@ -83,12 +89,14 @@ protected: int m_iMinY; int m_iMaxY; - BOOL m_bButtons[2]; + bool m_bButtons[2]; // + // todo: remove m_bActive: + // - instantiate CMouseInterface object when active (and delete when inactive) bool m_bActive; // Mouse h/w is active within the Apple][ VM - bool m_bEnabled; // Windows' mouse events get passed to Apple]['s mouse h/w + bool m_bEnabled; // Windows' mouse events get passed to Apple]['s mouse h/w (m_bEnabled == true implies that m_bActive == true) LPBYTE m_pSlotRom; UINT m_uSlot; }; diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 5894c4e2..44bcc42c 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -99,7 +99,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Globals (Public) ___________________________________________________ uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262 - uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible + uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible (NB. final hpos is 2 cycles long, so a line is 65 cycles) // Globals (Private) __________________________________________________ static int g_nVideoCharSet = 0; @@ -1449,7 +1449,7 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) g_aHorzClockVideoMode[ h ] = bVideoModeFlags; g_nVideoMixed = bVideoModeFlags & VF_MIXED; - g_nVideoCharSet = g_nAltCharSetOffset != 0; + g_nVideoCharSet = VideoGetSWAltCharSet() ? 1 : 0; g_nTextPage = 1; g_nHiresPage = 1; @@ -1654,19 +1654,21 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit } //=========================================================================== -void NTSC_VideoInitAppleType () +void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ) { int model = g_Apple2Type; - // anything other than low bit set means not II/II+ + // anything other than low bit set means not II/II+ (TC: include Pravets machines too?) if (model & 0xFFFE) g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; else g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; - g_nVideoClockVert = 0; - g_nVideoClockHorz = 0; - + // TC: Move these to a better place (as init'ing these 2 vars is nothing to do with g_Apple2Type) + _ASSERT(cyclesThisFrame < VIDEO_SCANNER_6502_CYCLES); + if (cyclesThisFrame >= VIDEO_SCANNER_6502_CYCLES) cyclesThisFrame = 0; // error + g_nVideoClockVert = (uint16_t) (cyclesThisFrame / VIDEO_SCANNER_MAX_HORZ); + g_nVideoClockHorz = cyclesThisFrame % VIDEO_SCANNER_MAX_HORZ; } //=========================================================================== diff --git a/source/NTSC.h b/source/NTSC.h index 3c53caf4..a6f3adec 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -13,7 +13,7 @@ extern uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV ); extern uint16_t NTSC_VideoGetScannerAddress( unsigned long cycles6502 ); extern void NTSC_VideoInit( uint8_t *pFramebuffer ); - extern void NTSC_VideoInitAppleType (); + extern void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ); extern void NTSC_VideoInitChroma(); extern bool NTSC_VideoIsVbl(); extern void NTSC_VideoUpdateCycles( long cycles6502 ); diff --git a/source/ParallelPrinter.cpp b/source/ParallelPrinter.cpp index 2ef531a6..f17609db 100644 --- a/source/ParallelPrinter.cpp +++ b/source/ParallelPrinter.cpp @@ -32,22 +32,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Memory.h" #include "ParallelPrinter.h" #include "Registry.h" +#include "YamlHelper.h" #include "..\resource\resource.h" static DWORD inactivity = 0; +static unsigned int g_PrinterIdleLimit = 10; static FILE* file = NULL; DWORD const PRINTDRVR_SIZE = APPLE_SLOT_SIZE; -TCHAR filepath[MAX_PATH * 2]; #define DEFAULT_PRINT_FILENAME "Printer.txt" static char g_szPrintFilename[MAX_PATH] = {0}; bool g_bDumpToPrinter = false; bool g_bConvertEncoding = true; bool g_bFilterUnprintable = true; bool g_bPrinterAppend = false; -int g_iPrinterIdleLimit = 10; bool g_bEnableDumpToRealPrinter = false; +static UINT g_uSlot = 0; + //=========================================================================== static BYTE __stdcall PrintStatus(WORD, WORD, BYTE, BYTE, ULONG); @@ -79,6 +81,8 @@ VOID PrintLoadRom(LPBYTE pCxRomPeripheral, const UINT uSlot) // RegisterIoHandler(uSlot, PrintStatus, PrintTransmit, NULL, NULL, NULL, NULL); + + g_uSlot = uSlot; } //=========================================================================== @@ -242,11 +246,79 @@ void Printer_SetFilename(char* prtFilename) unsigned int Printer_GetIdleLimit() { - return g_iPrinterIdleLimit; + return g_PrinterIdleLimit; } -//unsigned int void Printer_SetIdleLimit(unsigned int Duration) { - g_iPrinterIdleLimit = Duration; + g_PrinterIdleLimit = Duration; +} + +//=========================================================================== + +#define SS_YAML_VALUE_CARD_PRINTER "Generic Printer" + +#define SS_YAML_KEY_INACTIVITY "Inactivity" +#define SS_YAML_KEY_IDLELIMIT "Printer Idle Limit" +#define SS_YAML_KEY_FILENAME "Print Filename" +#define SS_YAML_KEY_FILEOPEN "Is File Open" +#define SS_YAML_KEY_DUMPTOPRINTER "Dump To Printer" +#define SS_YAML_KEY_CONVERTENCODING "Convert Encoding" +#define SS_YAML_KEY_FILTERUNPRINTABLE "Filter Unprintable" +#define SS_YAML_KEY_APPEND "Printer Append" +#define SS_YAML_KEY_DUMPTOREALPRINTER "Enable Dump To Real Printer" + +std::string Printer_GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_PRINTER); + return name; +} + +void Printer_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Slot slot(yamlSaveHelper, Printer_GetSnapshotCardName(), g_uSlot, 1); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, inactivity); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IDLELIMIT, g_PrinterIdleLimit); + yamlSaveHelper.SaveString(SS_YAML_KEY_FILENAME, g_szPrintFilename); + yamlSaveHelper.SaveBool(SS_YAML_KEY_FILEOPEN, (file != NULL) ? true : false); + yamlSaveHelper.SaveBool(SS_YAML_KEY_DUMPTOPRINTER, g_bDumpToPrinter); + yamlSaveHelper.SaveBool(SS_YAML_KEY_CONVERTENCODING, g_bConvertEncoding); + yamlSaveHelper.SaveBool(SS_YAML_KEY_FILTERUNPRINTABLE, g_bFilterUnprintable); + yamlSaveHelper.SaveBool(SS_YAML_KEY_APPEND, g_bPrinterAppend); + yamlSaveHelper.SaveBool(SS_YAML_KEY_DUMPTOREALPRINTER, g_bEnableDumpToRealPrinter); +} + +bool Printer_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 1) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + inactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); + g_PrinterIdleLimit = yamlLoadHelper.LoadUint(SS_YAML_KEY_IDLELIMIT); + strncpy(g_szPrintFilename, yamlLoadHelper.LoadString(SS_YAML_KEY_FILENAME).c_str(), sizeof(g_szPrintFilename)); + + if (yamlLoadHelper.LoadBool(SS_YAML_KEY_FILEOPEN)) + { + yamlLoadHelper.LoadBool(SS_YAML_KEY_APPEND); // Consume + g_bPrinterAppend = true; // Re-open print-file in append mode + BOOL bRes = CheckPrint(); + if (!bRes) + throw std::string("Printer Card: Unable to resume printing to file"); + } + else + { + g_bPrinterAppend = yamlLoadHelper.LoadBool(SS_YAML_KEY_APPEND); + } + + g_bDumpToPrinter = yamlLoadHelper.LoadBool(SS_YAML_KEY_DUMPTOPRINTER); + g_bConvertEncoding = yamlLoadHelper.LoadBool(SS_YAML_KEY_CONVERTENCODING); + g_bFilterUnprintable = yamlLoadHelper.LoadBool(SS_YAML_KEY_FILTERUNPRINTABLE); + g_bEnableDumpToRealPrinter = yamlLoadHelper.LoadBool(SS_YAML_KEY_DUMPTOREALPRINTER); + + return true; } diff --git a/source/ParallelPrinter.h b/source/ParallelPrinter.h index d2936a13..d2b96bdb 100644 --- a/source/ParallelPrinter.h +++ b/source/ParallelPrinter.h @@ -9,11 +9,12 @@ char* Printer_GetFilename(); void Printer_SetIdleLimit(unsigned int Duration); unsigned int Printer_GetIdleLimit(); +std::string Printer_GetSnapshotCardName(void); +void Printer_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +bool Printer_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + extern bool g_bDumpToPrinter; extern bool g_bConvertEncoding; extern bool g_bFilterUnprintable; extern bool g_bPrinterAppend; -extern int g_iPrinterIdleLimit; -extern bool g_bFilterUnprintable; -extern bool g_bPrinterAppend; extern bool g_bEnableDumpToRealPrinter; // Set by cmd-line: -printer-real diff --git a/source/Pravets.cpp b/source/Pravets.cpp new file mode 100644 index 00000000..296cf4f7 --- /dev/null +++ b/source/Pravets.cpp @@ -0,0 +1,48 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 1994-1996, Michael O'Brien +Copyright (C) 1999-2001, Oliver Schmidt +Copyright (C) 2002-2005, Tom Charlesworth +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Pravets - Apple II clone + * + * Author: Various + */ + +#include "StdAfx.h" + +#include "AppleWin.h" +#include "Frame.h" +#include "Keyboard.h" +#include "Tape.h" + +//Pravets 8A/C variables +bool P8CAPS_ON = false; +bool P8Shift = false; + +void PravetsReset(void) +{ + if (g_Apple2Type == A2TYPE_PRAVETS8A) + { + P8CAPS_ON = false; + TapeWrite(0, 0, 0, 0 ,0); + FrameRefreshStatus(DRAW_LEDS); + } +} diff --git a/source/Pravets.h b/source/Pravets.h new file mode 100644 index 00000000..801d1804 --- /dev/null +++ b/source/Pravets.h @@ -0,0 +1,7 @@ +#pragma once + +//Pravets 8A/C only variables +extern bool P8CAPS_ON; +extern bool P8Shift; + +void PravetsReset(void); diff --git a/source/SAM.cpp b/source/SAM.cpp new file mode 100644 index 00000000..2fa4c420 --- /dev/null +++ b/source/SAM.cpp @@ -0,0 +1,93 @@ +/* + AppleWin : An Apple //e emulator for Windows + + Copyright (C) 1994-1996, Michael O'Brien + Copyright (C) 1999-2001, Oliver Schmidt + Copyright (C) 2002-2005, Tom Charlesworth + Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski + + AppleWin is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + AppleWin is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with AppleWin; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + SAM.CPP + + Emulate an 8 bit DAC (eg: SAM card) which writes unsigned byte + data written to its IO area to the audio buffer (as used by the speaker). + This merges the data with the speaker stream, reducing the volume + of the Apple speaker when active. + + Riccardo Macri Mar 2015 +*/ +#include "StdAfx.h" + +#include "AppleWin.h" +#include "Memory.h" +#include "SAM.h" +#include "Speaker.h" + +// +// Write 8 bit data to speaker. Emulates a "SAM" speech card DAC +// + + +static BYTE __stdcall IOWrite_SAM(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) +{ + // Emulate audio from a SAM / 8 bit DAC card + // Only supportable if AppleWin is using WAVE output + // + // This works by using the existing speaker handling but then + // replacing the speaker audio with the 8 bit samples from the DAC + // before they get sent out to the soundcard buffer, whilst + // audio samples are being written to the SAM. + // + // Whilst very unusual, it is possible to intermingle use of SAM and the apple + // speaker. This is crudely supported with g_bQuieterSpeaker making the Apple + // speaker produce quieter clicks which will be crudely intermingled + // with the SAM data. The mute gets reset after the speaker code detects + // silence. + + if (soundtype != SOUND_WAVE) + return MemReadFloatingBus(nCyclesLeft); + + // use existing speaker code to bring timing up to date + BYTE res = SpkrToggle(pc, addr, bWrite, d, nCyclesLeft); + + // The DAC in the SAM uses unsigned 8 bit samples + // The WAV data that g_nSpeakerData is loaded into is a signed short + // + // We convert unsigned 8 bit to signed by toggling the most significant bit + // + // SAM card WAV driver SAM WAV + // 0xFF 255 0x7f 127 _ FF 7F + // 0x81 129 0x01 1 / \ + // 0x80 128 0x00 0 / \ /80 00 + // 0x7f 127 0xFF -1 \_/ + // 0x00 0 0x80 -128 00 80 + // + // SAM is 8 bit, PC WAV is 16 so shift audio to the MSB (<< 8) + + g_nSpeakerData = (d ^ 0x80) << 8; + + // make speaker quieter so eg: a metronome click through the + // Apple speaker is softer vs. the analogue SAM output. + g_bQuieterSpeaker = true; + + return res; +} + +void ConfigureSAM(LPBYTE pCxRomPeripheral, UINT uSlot) +{ + RegisterIoHandler(uSlot, IO_Null, IOWrite_SAM, IO_Null, IO_Null, NULL, NULL); +} diff --git a/source/SAM.h b/source/SAM.h new file mode 100644 index 00000000..291ac5c0 --- /dev/null +++ b/source/SAM.h @@ -0,0 +1,3 @@ +#pragma once + +void ConfigureSAM(LPBYTE pCxRomPeripheral, UINT uSlot); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 6587e458..3a771cd8 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth -Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,11 +23,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: Save-state (snapshot) module * - * Author: Copyright (c) 2004-2006 Tom Charlesworth + * Author: Copyright (c) 2004-2015 Tom Charlesworth */ #include "StdAfx.h" +#include "SaveState_Structs_v1.h" +#include "YamlHelper.h" + #include "AppleWin.h" #include "CPU.h" #include "Disk.h" @@ -36,17 +39,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Keyboard.h" #include "Memory.h" #include "Mockingboard.h" +#include "MouseInterface.h" +#include "ParallelPrinter.h" +#include "Pravets.h" #include "SerialComms.h" #include "Speaker.h" +#include "Speech.h" #include "Video.h" +#include "z80emu.h" -// Prototypes (Public) - // Note: This is here and not in Video.h to prevent header include bloat. - // i.e. so we don't need to incude "Structs.h" for NTSC.cpp - DWORD VideoGetSnapshot(SS_IO_Video* pSS); - DWORD VideoSetSnapshot(SS_IO_Video* pSS); +#include "Configuration\Config.h" +#include "Configuration\IPropertySheet.h" -#define DEFAULT_SNAPSHOT_NAME "SaveState.aws" + +#define DEFAULT_SNAPSHOT_NAME "SaveState.aws.yaml" bool g_bSaveStateOnExit = false; @@ -54,6 +60,13 @@ static std::string g_strSaveStateFilename; static std::string g_strSaveStatePathname; static std::string g_strSaveStatePath; +static YamlHelper yamlHelper; + +#define SS_FILE_VER 2 + +#define UNIT_APPLE2_VER 1 +#define UNIT_SLOTS_VER 1 + //----------------------------------------------------------------------------- void Snapshot_SetFilename(std::string strPathname) @@ -98,22 +111,27 @@ const char* Snapshot_GetPath() //----------------------------------------------------------------------------- -void Snapshot_LoadState() +static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) AppleWin v1.25.0 { - char szMessage[32 + MAX_PATH]; - std::string strOldImageDir; + std::string strOldImageDir(g_sCurrentDir); - APPLEWIN_SNAPSHOT* pSS = (APPLEWIN_SNAPSHOT*) new char[sizeof(APPLEWIN_SNAPSHOT)]; + APPLEWIN_SNAPSHOT_v1* pSS = (APPLEWIN_SNAPSHOT_v1*) new char[sizeof(APPLEWIN_SNAPSHOT_v1)]; // throw's bad_alloc try { - strOldImageDir = g_sCurrentDir; +#if _MSC_VER >= 1600 // static_assert supported from VS2010 (cl.exe v16.00) + static_assert(kSnapshotSize_v1 == sizeof(APPLEWIN_SNAPSHOT_v1), "Save-state v1 struct size mismatch"); +#else + // A compile error here means sizeof(APPLEWIN_SNAPSHOT_v1) is wrong, eg. one of the constituent structs has been modified + typedef char VerifySizesAreEqual[kSnapshotSize_v1 == sizeof(APPLEWIN_SNAPSHOT_v1) ? 1 : -1]; +#endif + + if (kSnapshotSize_v1 != sizeof(APPLEWIN_SNAPSHOT_v1)) + throw std::string("Save-state v1 struct size mismatch"); + SetCurrentImageDir(g_strSaveStatePath.c_str()); // Allow .dsk's load without prompting - if(pSS == NULL) - throw(0); - - memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT)); + memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT_v1)); // @@ -126,49 +144,32 @@ void Snapshot_LoadState() NULL); if(hFile == INVALID_HANDLE_VALUE) - { - strcpy(szMessage, "File not found: "); - strcpy(szMessage + strlen(szMessage), g_strSaveStatePathname.c_str()); - throw(0); - } + throw std::string("File not found: ") + g_strSaveStatePathname; DWORD dwBytesRead; BOOL bRes = ReadFile( hFile, pSS, - sizeof(APPLEWIN_SNAPSHOT), + sizeof(APPLEWIN_SNAPSHOT_v1), &dwBytesRead, NULL); CloseHandle(hFile); - if(!bRes || (dwBytesRead != sizeof(APPLEWIN_SNAPSHOT))) - { + if(!bRes || (dwBytesRead != sizeof(APPLEWIN_SNAPSHOT_v1))) // File size wrong: probably because of version mismatch or corrupt file - strcpy(szMessage, "File size mismatch"); - throw(0); - } + throw std::string("File size mismatch"); if(pSS->Hdr.dwTag != AW_SS_TAG) - { - strcpy(szMessage, "File corrupt"); - throw(0); - } + throw std::string("File corrupt"); if(pSS->Hdr.dwVersion != MAKE_VERSION(1,0,0,1)) - { - strcpy(szMessage, "Version mismatch"); - throw(0); - } + throw std::string("Version mismatch"); // TO DO: Verify checksum // // Reset all sub-systems MemReset(); - - if (!IS_APPLE2) - MemResetPaging(); - DiskReset(); KeybReset(); VideoResetState(); @@ -178,38 +179,46 @@ void Snapshot_LoadState() // Apple2 unit // - CpuSetSnapshot(&pSS->Apple2Unit.CPU6502); - sg_SSC.CommSetSnapshot(&pSS->Apple2Unit.Comms); - JoySetSnapshot(&pSS->Apple2Unit.Joystick); - KeybSetSnapshot(&pSS->Apple2Unit.Keyboard); - SpkrSetSnapshot(&pSS->Apple2Unit.Speaker); - VideoSetSnapshot(&pSS->Apple2Unit.Video); - MemSetSnapshot(&pSS->Apple2Unit.Memory); + SS_CPU6502& CPU = pSS->Apple2Unit.CPU6502; + CpuSetSnapshot_v1(CPU.A, CPU.X, CPU.Y, CPU.P, CPU.S, CPU.PC, CPU.nCumulativeCycles); + + SS_IO_Comms& SSC = pSS->Apple2Unit.Comms; + sg_SSC.SetSnapshot_v1(SSC.baudrate, SSC.bytesize, SSC.commandbyte, SSC.comminactivity, SSC.controlbyte, SSC.parity, SSC.stopbits); + + JoySetSnapshot_v1(pSS->Apple2Unit.Joystick.nJoyCntrResetCycle); + KeybSetSnapshot_v1(pSS->Apple2Unit.Keyboard.nLastKey); + SpkrSetSnapshot_v1(pSS->Apple2Unit.Speaker.nSpkrLastCycle); + VideoSetSnapshot_v1(pSS->Apple2Unit.Video.bAltCharSet, pSS->Apple2Unit.Video.dwVidMode); + MemSetSnapshot_v1(pSS->Apple2Unit.Memory.dwMemMode, pSS->Apple2Unit.Memory.bLastWriteRam, pSS->Apple2Unit.Memory.nMemMain, pSS->Apple2Unit.Memory.nMemAux); // // // Slot4: Mockingboard - MB_SetSnapshot(&pSS->Mockingboard1, 4); + MB_SetSnapshot_v1(&pSS->Mockingboard1, 4); // // Slot5: Mockingboard - MB_SetSnapshot(&pSS->Mockingboard2, 5); + MB_SetSnapshot_v1(&pSS->Mockingboard2, 5); // // Slot6: Disk][ - DiskSetSnapshot(&pSS->Disk2, 6); + DiskSetSnapshot_v1(&pSS->Disk2); SetLoadedSaveStateFlag(true); + + MemUpdatePaging(TRUE); } - catch(int) + catch(std::string szMessage) { MessageBox( g_hFrameWindow, - szMessage, + szMessage.c_str(), TEXT("Load State"), MB_ICONEXCLAMATION | MB_SETFOREGROUND); SetCurrentImageDir(strOldImageDir.c_str()); + + PostMessage(g_hFrameWindow, WM_USER_RESTART, 0, 0); // Power-cycle VM (undoing all the new state just loaded) } delete [] pSS; @@ -217,104 +226,393 @@ void Snapshot_LoadState() //----------------------------------------------------------------------------- -void Snapshot_SaveState() +static HANDLE m_hFile = INVALID_HANDLE_VALUE; +static CConfigNeedingRestart m_ConfigNew; + +static std::string GetSnapshotUnitApple2Name(void) { - APPLEWIN_SNAPSHOT* pSS = (APPLEWIN_SNAPSHOT*) new char[sizeof(APPLEWIN_SNAPSHOT)]; - if(pSS == NULL) + static const std::string name("Apple2"); + return name; +} + +static std::string GetSnapshotUnitSlotsName(void) +{ + static const std::string name("Slots"); + return name; +} + +#define SS_YAML_KEY_MODEL "Model" + +#define SS_YAML_VALUE_APPLE2 "Apple][" +#define SS_YAML_VALUE_APPLE2PLUS "Apple][+" +#define SS_YAML_VALUE_APPLE2E "Apple//e" +#define SS_YAML_VALUE_APPLE2EENHANCED "Enhanced Apple//e" +#define SS_YAML_VALUE_APPLE2C "Apple2c" +#define SS_YAML_VALUE_PRAVETS82 "Pravets82" +#define SS_YAML_VALUE_PRAVETS8M "Pravets8M" +#define SS_YAML_VALUE_PRAVETS8A "Pravets8A" + +static eApple2Type ParseApple2Type(std::string type) +{ + if (type == SS_YAML_VALUE_APPLE2) return A2TYPE_APPLE2; + else if (type == SS_YAML_VALUE_APPLE2PLUS) return A2TYPE_APPLE2PLUS; + else if (type == SS_YAML_VALUE_APPLE2E) return A2TYPE_APPLE2E; + else if (type == SS_YAML_VALUE_APPLE2EENHANCED) return A2TYPE_APPLE2EENHANCED; + else if (type == SS_YAML_VALUE_APPLE2C) return A2TYPE_APPLE2C; + else if (type == SS_YAML_VALUE_PRAVETS82) return A2TYPE_PRAVETS82; + else if (type == SS_YAML_VALUE_PRAVETS8M) return A2TYPE_PRAVETS8M; + else if (type == SS_YAML_VALUE_PRAVETS8A) return A2TYPE_PRAVETS8A; + + throw std::string("Load: Unknown Apple2 type"); +} + +static std::string GetApple2TypeAsString(void) +{ + switch ( GetApple2Type() ) { - // To do - return; + case A2TYPE_APPLE2: return SS_YAML_VALUE_APPLE2; + case A2TYPE_APPLE2PLUS: return SS_YAML_VALUE_APPLE2PLUS; + case A2TYPE_APPLE2E: return SS_YAML_VALUE_APPLE2E; + case A2TYPE_APPLE2EENHANCED:return SS_YAML_VALUE_APPLE2EENHANCED; + case A2TYPE_APPLE2C: return SS_YAML_VALUE_APPLE2C; + case A2TYPE_PRAVETS82: return SS_YAML_VALUE_PRAVETS82; + case A2TYPE_PRAVETS8M: return SS_YAML_VALUE_PRAVETS8M; + case A2TYPE_PRAVETS8A: return SS_YAML_VALUE_PRAVETS8A; + default: + throw std::string("Save: Unknown Apple2 type"); + } +} + +//--- + +static UINT ParseFileHdr(void) +{ + std::string scalar; + if (!yamlHelper.GetScalar(scalar)) + throw std::string(SS_YAML_KEY_FILEHDR ": Failed to find scalar"); + + if (scalar != SS_YAML_KEY_FILEHDR) + throw std::string("Failed to find file header"); + + yamlHelper.GetMapStartEvent(); + + YamlLoadHelper yamlLoadHelper(yamlHelper); + + // + + std::string value = yamlLoadHelper.LoadString(SS_YAML_KEY_TAG); + if (value != SS_YAML_VALUE_AWSS) + { + //printf("%s: Bad tag (%s) - expected %s\n", SS_YAML_KEY_FILEHDR, value.c_str(), SS_YAML_VALUE_AWSS); + throw std::string(SS_YAML_KEY_FILEHDR ": Bad tag"); } - memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT)); + return yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION); +} - pSS->Hdr.dwTag = AW_SS_TAG; - pSS->Hdr.dwVersion = MAKE_VERSION(1,0,0,1); - pSS->Hdr.dwChecksum = 0; // TO DO +//--- - // - // Apple2 unit - // +static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version) +{ + if (version != UNIT_APPLE2_VER) + throw std::string(SS_YAML_KEY_UNIT ": Apple2: Version mismatch"); - pSS->Apple2Unit.UnitHdr.dwLength = sizeof(SS_APPLE2_Unit); - pSS->Apple2Unit.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); + std::string model = yamlLoadHelper.LoadString(SS_YAML_KEY_MODEL); + SetApple2Type( ParseApple2Type(model) ); // NB. Sets default main CPU type + m_ConfigNew.m_Apple2Type = GetApple2Type(); - CpuGetSnapshot(&pSS->Apple2Unit.CPU6502); - sg_SSC.CommGetSnapshot(&pSS->Apple2Unit.Comms); - JoyGetSnapshot(&pSS->Apple2Unit.Joystick); - KeybGetSnapshot(&pSS->Apple2Unit.Keyboard); - SpkrGetSnapshot(&pSS->Apple2Unit.Speaker); - VideoGetSnapshot(&pSS->Apple2Unit.Video); - MemGetSnapshot(&pSS->Apple2Unit.Memory); + CpuLoadSnapshot(yamlLoadHelper); // NB. Overrides default main CPU type + m_ConfigNew.m_CpuType = GetMainCpu(); - // - // Slot1: Empty - pSS->Empty1.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY); - pSS->Empty1.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); - pSS->Empty1.Hdr.dwSlot = 1; - pSS->Empty1.Hdr.dwType = CT_Empty; + JoyLoadSnapshot(yamlLoadHelper); + KeybLoadSnapshot(yamlLoadHelper); + SpkrLoadSnapshot(yamlLoadHelper); + VideoLoadSnapshot(yamlLoadHelper); + MemLoadSnapshot(yamlLoadHelper); +} - // - // Slot2: Empty - pSS->Empty2.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY); - pSS->Empty2.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); - pSS->Empty2.Hdr.dwSlot = 2; - pSS->Empty2.Hdr.dwType = CT_Empty; +//--- - // - // Slot3: Empty - pSS->Empty3.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY); - pSS->Empty3.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); - pSS->Empty3.Hdr.dwSlot = 3; - pSS->Empty3.Hdr.dwType = CT_Empty; +static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version) +{ + if (version != UNIT_SLOTS_VER) + throw std::string(SS_YAML_KEY_UNIT ": Slots: Version mismatch"); - // - // Slot4: Mockingboard - MB_GetSnapshot(&pSS->Mockingboard1, 4); - - // - // Slot5: Mockingboard - MB_GetSnapshot(&pSS->Mockingboard2, 5); - - // - // Slot6: Disk][ - DiskGetSnapshot(&pSS->Disk2, 6); - - // - - HANDLE hFile = CreateFile( g_strSaveStatePathname.c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - DWORD dwError = GetLastError(); - _ASSERT((dwError == 0) || (dwError == ERROR_ALREADY_EXISTS)); - - if(hFile != INVALID_HANDLE_VALUE) + while (1) { - DWORD dwBytesWritten; - BOOL bRes = WriteFile( hFile, - pSS, - sizeof(APPLEWIN_SNAPSHOT), - &dwBytesWritten, - NULL); + std::string scalar = yamlLoadHelper.GetMapNextSlotNumber(); + if (scalar.empty()) + break; // done all slots - if(!bRes || (dwBytesWritten != sizeof(APPLEWIN_SNAPSHOT))) - dwError = GetLastError(); + const int slot = strtoul(scalar.c_str(), NULL, 10); // NB. aux slot supported as a different "unit" + if (slot < 1 || slot > 7) + throw std::string("Slots: Invalid slot #: ") + scalar; - CloseHandle(hFile); + yamlLoadHelper.GetSubMap(scalar); + + std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD); + UINT version = yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION); + + if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE))) + throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE); + + bool bIsCardSupported = true; + SS_CARDTYPE type = CT_Empty; + bool bRes = false; + + if (card == Printer_GetSnapshotCardName()) + { + bRes = Printer_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_GenericPrinter; + } + else if (card == sg_SSC.GetSnapshotCardName()) + { + bRes = sg_SSC.LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_SSC; + } + else if (card == sg_Mouse.GetSnapshotCardName()) + { + bRes = sg_Mouse.LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_MouseInterface; + } + else if (card == Z80_GetSnapshotCardName()) + { + bRes = Z80_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_Z80; + } + else if (card == MB_GetSnapshotCardName()) + { + bRes = MB_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_MockingboardC; + } + else if (card == Phasor_GetSnapshotCardName()) + { + bRes = Phasor_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_Phasor; + } + else if (card == DiskGetSnapshotCardName()) + { + bRes = DiskLoadSnapshot(yamlLoadHelper, slot, version); + type = CT_Disk2; + } + else if (card == HD_GetSnapshotCardName()) + { + bRes = HD_LoadSnapshot(yamlLoadHelper, slot, version, g_strSaveStatePath); + m_ConfigNew.m_bEnableHDD = true; + type = CT_GenericHDD; + } + else + { + bIsCardSupported = false; + throw std::string("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue + } + + if (bRes && bIsCardSupported) + { + m_ConfigNew.m_Slot[slot] = type; + } + + yamlLoadHelper.PopMap(); + yamlLoadHelper.PopMap(); + } +} + +//--- + +static void ParseUnit(void) +{ + yamlHelper.GetMapStartEvent(); + + YamlLoadHelper yamlLoadHelper(yamlHelper); + + std::string unit = yamlLoadHelper.LoadString(SS_YAML_KEY_TYPE); + UINT version = yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION); + + if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE))) + throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE); + + if (unit == GetSnapshotUnitApple2Name()) + { + ParseUnitApple2(yamlLoadHelper, version); + } + else if (unit == MemGetSnapshotUnitAuxSlotName()) + { + MemLoadSnapshotAux(yamlLoadHelper, version); + } + else if (unit == GetSnapshotUnitSlotsName()) + { + ParseSlots(yamlLoadHelper, version); } else { - dwError = GetLastError(); + throw std::string(SS_YAML_KEY_UNIT ": Unknown type: " ) + unit; + } +} + +static void Snapshot_LoadState_v2(void) +{ + try + { + int res = yamlHelper.InitParser( g_strSaveStatePathname.c_str() ); + if (!res) + throw std::string("Failed to initialize parser or open file"); // TODO: disambiguate + + UINT version = ParseFileHdr(); + if (version != SS_FILE_VER) + throw std::string("Version mismatch"); + + // + + CConfigNeedingRestart ConfigOld; + ConfigOld.m_Slot[1] = CT_GenericPrinter; // fixme + ConfigOld.m_Slot[2] = CT_SSC; // fixme + //ConfigOld.m_Slot[3] = CT_Uthernet; // todo + ConfigOld.m_Slot[6] = CT_Disk2; // fixme + ConfigOld.m_Slot[7] = ConfigOld.m_bEnableHDD ? CT_GenericHDD : CT_Empty; // fixme + //ConfigOld.m_SlotAux = ?; // fixme + + for (UINT i=0; ibaudrate = m_uBaudRate; - pSS->bytesize = m_uByteSize; - pSS->commandbyte = m_uCommandByte; - pSS->comminactivity = m_dwCommInactivity; - pSS->controlbyte = m_uControlByte; - pSS->parity = m_uParity; -// memcpy(pSS->recvbuffer, m_RecvBuffer, uRecvBufferSize); - pSS->recvbytes = 0; - pSS->stopbits = m_uStopBits; - return 0; + m_uBaudRate = baudrate; + m_uByteSize = bytesize; + m_uCommandByte = commandbyte; + m_dwCommInactivity = comminactivity; + m_uControlByte = controlbyte; + m_uParity = parity; +// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); +// m_vRecvBytes = recvbytes; + m_uStopBits = stopbits; } -DWORD CSuperSerialCard::CommSetSnapshot(SS_IO_Comms* pSS) +//=========================================================================== + +#define SS_YAML_VALUE_CARD_SSC "Super Serial Card" + +#define SS_YAML_KEY_DIPSWDEFAULT "DIPSW Default" +#define SS_YAML_KEY_DIPSWCURRENT "DIPSW Current" + +#define SS_YAML_KEY_BAUDRATE "Baud Rate" +#define SS_YAML_KEY_FWMODE "Firmware mode" +#define SS_YAML_KEY_STOPBITS "Stop Bits" +#define SS_YAML_KEY_BYTESIZE "Byte Size" +#define SS_YAML_KEY_PARITY "Parity" +#define SS_YAML_KEY_LINEFEED "Linefeed" +#define SS_YAML_KEY_INTERRUPTS "Interrupts" +#define SS_YAML_KEY_CONTROL "Control Byte" +#define SS_YAML_KEY_COMMAND "Command Byte" +#define SS_YAML_KEY_INACTIVITY "Comm Inactivity" +#define SS_YAML_KEY_TXIRQENABLED "TX IRQ Enabled" +#define SS_YAML_KEY_RXIRQENABLED "RX IRQ Enabled" +#define SS_YAML_KEY_TXIRQPENDING "TX IRQ Pending" +#define SS_YAML_KEY_RXIRQPENDING "RX IRQ Pending" +#define SS_YAML_KEY_WRITTENTX "Written TX" +#define SS_YAML_KEY_SERIALPORTNAME "Serial Port Name" + +std::string CSuperSerialCard::GetSnapshotCardName(void) { - m_uBaudRate = pSS->baudrate; - m_uByteSize = pSS->bytesize; - m_uCommandByte = pSS->commandbyte; - m_dwCommInactivity = pSS->comminactivity; - m_uControlByte = pSS->controlbyte; - m_uParity = pSS->parity; -// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); -// m_vRecvBytes = pSS->recvbytes; - m_uStopBits = pSS->stopbits; - return 0; + static const std::string name(SS_YAML_VALUE_CARD_SSC); + return name; +} + +void CSuperSerialCard::SaveSnapshotDIPSW(YamlSaveHelper& yamlSaveHelper, std::string key, SSC_DIPSW& dipsw) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", key.c_str()); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, dipsw.uBaudRate); + yamlSaveHelper.SaveUint(SS_YAML_KEY_FWMODE, dipsw.eFirmwareMode); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, dipsw.uStopBits); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, dipsw.uByteSize); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, dipsw.uParity); + yamlSaveHelper.SaveBool(SS_YAML_KEY_LINEFEED, dipsw.bLinefeed); + yamlSaveHelper.SaveBool(SS_YAML_KEY_INTERRUPTS, dipsw.bInterrupts); +} + +void CSuperSerialCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_uSlot, 1); + + YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + SaveSnapshotDIPSW(yamlSaveHelper, SS_YAML_KEY_DIPSWDEFAULT, m_DIPSWDefault); + SaveSnapshotDIPSW(yamlSaveHelper, SS_YAML_KEY_DIPSWCURRENT, m_DIPSWCurrent); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, m_uBaudRate); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, m_uStopBits); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, m_uByteSize); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, m_uParity); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_CONTROL, m_uControlByte); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_uCommandByte); + yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, m_dwCommInactivity); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled); + yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQPENDING, m_vbTxIrqPending); + yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQPENDING, m_vbRxIrqPending); + yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITTENTX, m_bWrittenTx); + yamlSaveHelper.SaveString(SS_YAML_KEY_SERIALPORTNAME, GetSerialPortName()); +} + +void CSuperSerialCard::LoadSnapshotDIPSW(YamlLoadHelper& yamlLoadHelper, std::string key, SSC_DIPSW& dipsw) +{ + if (!yamlLoadHelper.GetSubMap(key)) + throw std::string("Card: Expected key: " + key); + + dipsw.uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); + dipsw.eFirmwareMode = (eFWMODE) yamlLoadHelper.LoadUint(SS_YAML_KEY_FWMODE); + dipsw.uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); + dipsw.uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); + dipsw.uParity = yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); + dipsw.bLinefeed = yamlLoadHelper.LoadBool(SS_YAML_KEY_LINEFEED); + dipsw.bInterrupts = yamlLoadHelper.LoadBool(SS_YAML_KEY_INTERRUPTS); + + yamlLoadHelper.PopMap(); +} + +bool CSuperSerialCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 2) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + LoadSnapshotDIPSW(yamlLoadHelper, SS_YAML_KEY_DIPSWDEFAULT, m_DIPSWDefault); + LoadSnapshotDIPSW(yamlLoadHelper, SS_YAML_KEY_DIPSWCURRENT, m_DIPSWCurrent); + + m_uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); + m_uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); + m_uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); + m_uParity = yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); + m_uControlByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_CONTROL); + m_uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND); + m_dwCommInactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); + m_bTxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); + m_bRxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); + m_vbTxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQPENDING); + m_vbRxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQPENDING); + m_bWrittenTx = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITTENTX); + + std::string serialPortName = yamlLoadHelper.LoadString(SS_YAML_KEY_SERIALPORTNAME); + SetSerialPortName(serialPortName.c_str()); + + return true; } diff --git a/source/SerialComms.h b/source/SerialComms.h index d75d2ea9..c86678d2 100644 --- a/source/SerialComms.h +++ b/source/SerialComms.h @@ -33,8 +33,10 @@ public: void CommDestroy(); void CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem); void CommUpdate(DWORD); - DWORD CommGetSnapshot(SS_IO_Comms* pSS); - DWORD CommSetSnapshot(SS_IO_Comms* pSS); + void SetSnapshot_v1(const DWORD baudrate, const BYTE bytesize, const BYTE commandbyte, const DWORD comminactivity, const BYTE controlbyte, const BYTE parity, const BYTE stopbits); + std::string GetSnapshotCardName(void); + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); char* GetSerialPortChoices(); DWORD GetSerialPort() { return m_dwSerialPortItem; } // Drop-down list item @@ -72,6 +74,8 @@ private: void CommThUninit(); UINT GetNumSerialPortChoices() { return m_vecSerialPortsItems.size(); } void ScanCOMPorts(); + void SaveSnapshotDIPSW(class YamlSaveHelper& yamlSaveHelper, std::string key, SSC_DIPSW& dipsw); + void LoadSnapshotDIPSW(class YamlLoadHelper& yamlLoadHelper, std::string key, SSC_DIPSW& dipsw); // @@ -134,4 +138,5 @@ private: OVERLAPPED m_o; BYTE* m_pExpansionRom; + UINT m_uSlot; }; diff --git a/source/Speaker.cpp b/source/Speaker.cpp index 3608ecd6..fcf1dd9f 100644 --- a/source/Speaker.cpp +++ b/source/Speaker.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "SoundCore.h" #include "Speaker.h" #include "Video.h" // VideoRedrawScreen() +#include "YamlHelper.h" #include "Debugger\Debug.h" // For DWORD extbench @@ -51,11 +52,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // their buffers are running low. // -#define SOUND_NONE 0 -#define SOUND_DIRECT 1 -#define SOUND_SMART 2 -#define SOUND_WAVE 3 - static const unsigned short g_nSPKR_NumChannels = 1; static const DWORD g_dwDSSpkrBufferSize = MAX_SAMPLES * sizeof(short) * g_nSPKR_NumChannels; @@ -66,18 +62,20 @@ static short* g_pSpeakerBuffer = NULL; // Globals (SOUND_WAVE) const short SPKR_DATA_INIT = (short)0x8000; -static short g_nSpeakerData = SPKR_DATA_INIT; +short g_nSpeakerData = SPKR_DATA_INIT; static UINT g_nBufferIdx = 0; static short* g_pRemainderBuffer = NULL; static UINT g_nRemainderBufferSize; // Setup in SpkrInitialize() static UINT g_nRemainderBufferIdx; // Setup in SpkrInitialize() - // Application-wide globals: DWORD soundtype = SOUND_WAVE; double g_fClksPerSpkrSample; // Setup in SetClksPerSpkrSample() +// Allow temporary quietening of speaker (8 bit DAC) +bool g_bQuieterSpeaker = false; + // Globals static DWORD lastcyclenum = 0; static DWORD toggles = 0; @@ -226,7 +224,7 @@ void SpkrDestroy () g_pSpeakerBuffer = NULL; g_pRemainderBuffer = NULL; } - else + else if (soundtype == SOUND_DIRECT || soundtype == SOUND_SMART) { InternalBeep(0,0); } @@ -328,8 +326,8 @@ void SpkrReset() BOOL SpkrSetEmulationType (HWND window, DWORD newtype) { - if (soundtype != SOUND_NONE) - SpkrDestroy(); + SpkrDestroy(); // GH#295: Destroy for all types (even SOUND_NONE) + soundtype = newtype; if (soundtype != SOUND_NONE) SpkrInitialize(); @@ -447,7 +445,21 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft) UpdateSpkr(); - g_nSpeakerData = ~g_nSpeakerData; + if (g_bQuieterSpeaker) + { + // quieten the speaker if 8 bit DAC in use + if (g_nSpeakerData == (SPKR_DATA_INIT >> 2)) + g_nSpeakerData = ~g_nSpeakerData; + else + g_nSpeakerData = SPKR_DATA_INIT>>2; + } + else + { + if (g_nSpeakerData == SPKR_DATA_INIT) + g_nSpeakerData = ~g_nSpeakerData; + else + g_nSpeakerData = SPKR_DATA_INIT; + } } else if (soundtype != SOUND_NONE) { @@ -875,7 +887,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples) double fTicksSecs = (double)GetTickCount() / 1000.0; sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg); - if (g_fh) fprintf(g_fh, szDbg); + if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; nNumSamplesError = 0; @@ -993,6 +1005,7 @@ static void Spkr_SetActive(bool bActive) // Called by SpkrUpdate() after 0.2s of speaker inactivity g_bSpkrRecentlyActive = false; SpeakerVoice.bRecentlyActive = false; + g_bQuieterSpeaker = 0; // undo any muting (for 8 bit DAC) } } @@ -1080,14 +1093,33 @@ void Spkr_DSUninit() //============================================================================= -DWORD SpkrGetSnapshot(SS_IO_Speaker* pSS) +void SpkrSetSnapshot_v1(const unsigned __int64 SpkrLastCycle) { - pSS->g_nSpkrLastCycle = g_nSpkrLastCycle; - return 0; + g_nSpkrLastCycle = SpkrLastCycle; } -DWORD SpkrSetSnapshot(SS_IO_Speaker* pSS) +// + +#define SS_YAML_KEY_LASTCYCLE "Last Cycle" + +static std::string SpkrGetSnapshotStructName(void) { - g_nSpkrLastCycle = pSS->g_nSpkrLastCycle; - return 0; + static const std::string name("Speaker"); + return name; +} + +void SpkrSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SpkrGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_LASTCYCLE, g_nSpkrLastCycle); +} + +void SpkrLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(SpkrGetSnapshotStructName())) + return; + + g_nSpkrLastCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_LASTCYCLE); + + yamlLoadHelper.PopMap(); } diff --git a/source/Speaker.h b/source/Speaker.h index 8e93fbbe..2e6312bd 100644 --- a/source/Speaker.h +++ b/source/Speaker.h @@ -1,7 +1,14 @@ #pragma once +#define SOUND_NONE 0 +#define SOUND_DIRECT 1 +#define SOUND_SMART 2 +#define SOUND_WAVE 3 + extern DWORD soundtype; extern double g_fClksPerSpkrSample; +extern bool g_bQuieterSpeaker; +extern short g_nSpeakerData; void SpkrDestroy (); void SpkrInitialize (); @@ -19,7 +26,8 @@ void Spkr_Demute(); bool Spkr_IsActive(); bool Spkr_DSInit(); void Spkr_DSUninit(); -DWORD SpkrGetSnapshot(SS_IO_Speaker* pSS); -DWORD SpkrSetSnapshot(SS_IO_Speaker* pSS); +void SpkrSetSnapshot_v1(const unsigned __int64 SpkrLastCycle); +void SpkrSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void SpkrLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall SpkrToggle (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/StdAfx.h b/source/StdAfx.h index 989c60da..6befb99a 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -14,7 +14,7 @@ #endif // Not needed in VC7.1, but needed in VC Express -#include +#include #include #include @@ -23,7 +23,6 @@ #include #include #include -#include #include #if _MSC_VER >= 1600 // supported from VS2010 (cl.exe v16.00) #include // cleanup WORD DWORD -> uint16_t uint32_t @@ -43,6 +42,8 @@ typedef UINT32 uint32_t; #include #include #include +#include +#include #include // SM_CXPADDEDBORDER is not supported on 2000 & XP: diff --git a/source/Structs.h b/source/Structs.h deleted file mode 100644 index f2af25ac..00000000 --- a/source/Structs.h +++ /dev/null @@ -1,285 +0,0 @@ -#pragma once - -#include "DiskDefs.h" - -// Structs used by save-state file - -// *** DON'T CHANGE ANY STRUCT WITHOUT CONSIDERING BACKWARDS COMPATIBILITY WITH .AWS FORMAT *** - -#define MAKE_VERSION(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | (d)) - -#define AW_SS_TAG 'SSWA' // 'AWSS' = AppleWin SnapShot - -typedef struct -{ - DWORD dwTag; // "AWSS" - DWORD dwVersion; - DWORD dwChecksum; -} SS_FILE_HDR; - -typedef struct -{ - DWORD dwLength; // Byte length of this unit struct - DWORD dwVersion; -} SS_UNIT_HDR; - -///////////////////////////////////////////////////////////////////////////////// - -const UINT nMemMainSize = 64*1024; -const UINT nMemAuxSize = 64*1024; - -typedef struct -{ - BYTE A; - BYTE X; - BYTE Y; - BYTE P; - BYTE S; - USHORT PC; - unsigned __int64 g_nCumulativeCycles; - // IRQ = OR-sum of all interrupt sources -} SS_CPU6502; - -const UINT uRecvBufferSize = 9; - -typedef struct -{ - DWORD baudrate; - BYTE bytesize; - BYTE commandbyte; - DWORD comminactivity; // If non-zero then COM port open - BYTE controlbyte; - BYTE parity; - BYTE recvbuffer[uRecvBufferSize]; - DWORD recvbytes; - BYTE stopbits; -} SS_IO_Comms; - -typedef struct -{ - unsigned __int64 g_nJoyCntrResetCycle; -} SS_IO_Joystick; - -typedef struct -{ - DWORD keyboardqueries; - BYTE nLastKey; -} SS_IO_Keyboard; - -//typedef struct -//{ -//} SS_IO_Memory; - -typedef struct -{ - unsigned __int64 g_nSpkrLastCycle; -} SS_IO_Speaker; - -typedef struct -{ - bool bAltCharSet; // charoffs - DWORD dwVidMode; -} SS_IO_Video; - -typedef struct -{ - DWORD dwMemMode; - BOOL bLastWriteRam; - BYTE nMemMain[nMemMainSize]; - BYTE nMemAux[nMemAuxSize]; -} SS_BaseMemory; - -typedef struct -{ - SS_UNIT_HDR UnitHdr; - SS_CPU6502 CPU6502; - SS_IO_Comms Comms; - SS_IO_Joystick Joystick; - SS_IO_Keyboard Keyboard; -// SS_IO_Memory Memory; - SS_IO_Speaker Speaker; - SS_IO_Video Video; - SS_BaseMemory Memory; -} SS_APPLE2_Unit; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - DWORD dwComputerEmulation; - bool bCustomSpeed; - DWORD dwEmulationSpeed; - bool bEnhancedDiskSpeed; - DWORD dwJoystickType[2]; - bool bMockingboardEnabled; - DWORD dwMonochromeColor; - DWORD dwSerialPort; - DWORD dwSoundType; // Sound Emulation - DWORD dwVideoType; // Video Emulation -} SS_AW_CFG; - -typedef struct -{ - char StartingDir[MAX_PATH]; - DWORD dwWindowXpos; - DWORD dwWindowYpos; -} SS_AW_PREFS; - -typedef struct -{ - SS_UNIT_HDR UnitHdr; - DWORD dwAppleWinVersion; - SS_AW_PREFS Prefs; - SS_AW_CFG Cfg; -} SS_APPLEWIN_CONFIG; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - SS_UNIT_HDR UnitHdr; - DWORD dwType; // SS_CARDTYPE - DWORD dwSlot; // [1..7] -} SS_CARD_HDR; - -enum SS_CARDTYPE -{ - CT_Empty = 0, - CT_Disk2, // Apple Disk][ - CT_SSC, // Apple Super Serial Card - CT_MockingboardC, // Soundcard - CT_GenericPrinter, - CT_GenericHDD, // Hard disk - CT_GenericClock, - CT_MouseInterface, - CT_Z80, - CT_Phasor, // Soundcard - CT_Echo, // Soundcard - CT_SAM, // Soundcard: Software Automated Mouth -}; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - SS_CARD_HDR Hdr; -} SS_CARD_EMPTY; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - char szFileName[MAX_PATH]; - int track; - int phase; - int byte; - BOOL writeprotected; - BOOL trackimagedata; - BOOL trackimagedirty; - DWORD spinning; - DWORD writelight; - int nibbles; - BYTE nTrack[NIBBLES_PER_TRACK]; -} DISK2_Unit; - -typedef struct -{ - SS_CARD_HDR Hdr; - DISK2_Unit Unit[2]; - WORD phases; - WORD currdrive; - BOOL diskaccessed; - BOOL enhancedisk; - BYTE floppylatch; - BOOL floppymotoron; - BOOL floppywritemode; -} SS_CARD_DISK2; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - union - { - struct - { - BYTE l; - BYTE h; - }; - USHORT w; - }; -} IWORD; - -typedef struct -{ - BYTE ORB; // $00 - Port B - BYTE ORA; // $01 - Port A (with handshaking) - BYTE DDRB; // $02 - Data Direction Register B - BYTE DDRA; // $03 - Data Direction Register A - // - // $04 - Read counter (L) / Write latch (L) - // $05 - Read / Write & initiate count (H) - // $06 - Read / Write & latch (L) - // $07 - Read / Write & latch (H) - // $08 - Read counter (L) / Write latch (L) - // $09 - Read counter (H) / Write latch (H) - IWORD TIMER1_COUNTER; - IWORD TIMER1_LATCH; - IWORD TIMER2_COUNTER; - IWORD TIMER2_LATCH; - // - BYTE SERIAL_SHIFT; // $0A - BYTE ACR; // $0B - Auxiliary Control Register - BYTE PCR; // $0C - Peripheral Control Register - BYTE IFR; // $0D - Interrupt Flag Register - BYTE IER; // $0E - Interrupt Enable Register - BYTE ORA_NO_HS; // $0F - Port A (without handshaking) -} SY6522; - -typedef struct -{ - BYTE DurationPhonome; - BYTE Inflection; // I10..I3 - BYTE RateInflection; - BYTE CtrlArtAmp; - BYTE FilterFreq; - // - BYTE CurrentMode; // b7:6=Mode; b0=D7 pin (for IRQ) -} SSI263A; - -typedef struct -{ - SY6522 RegsSY6522; - BYTE RegsAY8910[16]; - SSI263A RegsSSI263; - BYTE nAYCurrentRegister; - bool bTimer1IrqPending; - bool bTimer2IrqPending; - bool bSpeechIrqPending; -} MB_Unit; - -const UINT MB_UNITS_PER_CARD = 2; - -typedef struct -{ - SS_CARD_HDR Hdr; - MB_Unit Unit[MB_UNITS_PER_CARD]; -} SS_CARD_MOCKINGBOARD; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - SS_FILE_HDR Hdr; - SS_APPLE2_Unit Apple2Unit; -// SS_APPLEWIN_CONFIG AppleWinCfg; - SS_CARD_EMPTY Empty1; // Slot1 - SS_CARD_EMPTY Empty2; // Slot2 - SS_CARD_EMPTY Empty3; // Slot3 - SS_CARD_MOCKINGBOARD Mockingboard1; // Slot4 - SS_CARD_MOCKINGBOARD Mockingboard2; // Slot5 - SS_CARD_DISK2 Disk2; // Slot6 - SS_CARD_EMPTY Empty7; // Slot7 -} APPLEWIN_SNAPSHOT; - -///////////////////////////////////////////////////////////////////////////////// diff --git a/source/Tape.cpp b/source/Tape.cpp index 0aef7f03..33dd5872 100644 --- a/source/Tape.cpp +++ b/source/Tape.cpp @@ -24,8 +24,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: This module is created for emulation of the 8bit character mode (mode 1) switch, * which is located in $c060, and so far does not intend to emulate a tape device. * - * * Author: Various + * + * In comments, UTA2E is an abbreviation for a reference to "Understanding the Apple //e" by James Sather */ #include "StdAfx.h" @@ -33,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "AppleWin.h" #include "Keyboard.h" #include "Memory.h" +#include "Pravets.h" static bool g_CapsLockAllowed = false; @@ -76,7 +78,7 @@ BYTE __stdcall TapeRead(WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft) return C060; } - return (1<<7) | (MemReadFloatingBus(nCyclesLeft) & 0x7F); // Keep high-bit fixed (since TAPEIN isn't supported) + return MemReadFloatingBus(1, nCyclesLeft); // TAPEIN has high bit 1 when input is low or not connected (UTA2E page 7-5, 7-6) } /* diff --git a/source/Video.cpp b/source/Video.cpp index 0c5909a7..d24cd128 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "..\resource\resource.h" #include "Configuration\PropertySheet.h" #include "Debugger\Debugger_Color.h" // For NUM_DEBUG_COLORS +#include "YamlHelper.h" #define HALF_PIXEL_SOLID 1 #define HALF_PIXEL_BLEED 0 @@ -590,7 +591,6 @@ static inline int GetOriginal2EOffset(BYTE ch) } //=========================================================================== -#define ROL_NIB(x) ( (((x)<<1)&0xF) | (((x)>>3)&1) ) // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- @@ -1195,11 +1195,10 @@ void VideoRefreshScreen ( int bVideoModeFlags ) //=========================================================================== void VideoReinitialize () { - NTSC_VideoInitAppleType(); + NTSC_VideoInitAppleType(g_dwCyclesThisFrame); NTSC_SetVideoStyle(); } - //=========================================================================== void VideoResetState () { @@ -1220,8 +1219,8 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) switch (address) { - case 0x00: g_uVideoMode &= ~VF_80STORE; ; break; - case 0x01: g_uVideoMode |= VF_80STORE; ; break; + case 0x00: g_uVideoMode &= ~VF_80STORE; break; + case 0x01: g_uVideoMode |= VF_80STORE; break; case 0x0C: if (!IS_APPLE2){g_uVideoMode &= ~VF_80COL; NTSC_SetVideoTextMode(40);}; break; case 0x0D: if (!IS_APPLE2){g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80);}; break; case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off @@ -1238,7 +1237,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break; } - // Apple IIe, Techical Nodtes, #3: Double High-Resolution Graphics + // Apple IIe, Techical Notes, #3: Double High-Resolution Graphics // 80STORE must be OFF to display page 2 if (SW_80STORE) g_uVideoMode &= ~VF_PAGE2; @@ -1260,7 +1259,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) // NB. Deferring the update by just setting /g_VideoForceFullRedraw/ is not an option, since this doesn't provide "flip-immediate" // // Ultimately this isn't the correct solution, and proper cycle-accurate video rendering should be done, but this is a much bigger job! - // TODO: Is MemReadFloatingBus() still accurate now that we have proper per cycle video rendering?? + // TODO-Michael: Is MemReadFloatingBus() still accurate now that we have proper per cycle video rendering?? if (!g_bVideoUpdatedThisFrame) { @@ -1323,20 +1322,42 @@ void VideoSetForceFullRedraw(void) //=========================================================================== -DWORD VideoGetSnapshot(SS_IO_Video* pSS) +void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode) { - pSS->bAltCharSet = !(g_nAltCharSetOffset == 0); - pSS->dwVidMode = g_uVideoMode; - return 0; + g_nAltCharSetOffset = !AltCharSet ? 0 : 256; + g_uVideoMode = VideoMode; } -//=========================================================================== +// -DWORD VideoSetSnapshot(SS_IO_Video* pSS) +#define SS_YAML_KEY_ALTCHARSET "Alt Char Set" +#define SS_YAML_KEY_VIDEOMODE "Video Mode" +#define SS_YAML_KEY_CYCLESTHISFRAME "Cycles This Frame" + +static std::string VideoGetSnapshotStructName(void) { - g_nAltCharSetOffset = !pSS->bAltCharSet ? 0 : 256; - g_uVideoMode = pSS->dwVidMode; - return 0; + static const std::string name("Video"); + return name; +} + +void VideoSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", VideoGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveBool(SS_YAML_KEY_ALTCHARSET, g_nAltCharSetOffset ? true : false); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_VIDEOMODE, g_uVideoMode); + yamlSaveHelper.SaveUint(SS_YAML_KEY_CYCLESTHISFRAME, g_dwCyclesThisFrame); +} + +void VideoLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(VideoGetSnapshotStructName())) + return; + + g_nAltCharSetOffset = yamlLoadHelper.LoadBool(SS_YAML_KEY_ALTCHARSET) ? 256 : 0; + g_uVideoMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_VIDEOMODE); + g_dwCyclesThisFrame = yamlLoadHelper.LoadUint(SS_YAML_KEY_CYCLESTHISFRAME); + + yamlLoadHelper.PopMap(); } //=========================================================================== diff --git a/source/Video.h b/source/Video.h index ab935426..7bad49f7 100644 --- a/source/Video.h +++ b/source/Video.h @@ -152,12 +152,11 @@ struct WinBmpHeader4_t extern HBITMAP g_hLogoBitmap; -extern COLORREF g_nMonochromeRGB; // saved -extern uint32_t g_uVideoMode ; -extern DWORD g_eVideoType ; // saved -extern DWORD g_uHalfScanLines; // saved +extern COLORREF g_nMonochromeRGB; // saved to Registry +extern uint32_t g_uVideoMode; +extern DWORD g_eVideoType; // saved to Registry +extern DWORD g_uHalfScanLines; // saved to Registry extern uint8_t *g_pFramebufferbits; -extern int g_nAltCharSetOffset; // alternate character set typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int); @@ -177,7 +176,6 @@ void VideoReinitialize (); void VideoResetState (); WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); bool VideoGetVbl(DWORD uExecutedCycles); -void VideoEndOfVideoFrame(void); bool VideoGetSW80COL(void); bool VideoGetSWDHIRES(void); @@ -190,6 +188,10 @@ bool VideoGetSWAltCharSet(void); void VideoSetForceFullRedraw(void); +void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode); +void VideoSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void VideoLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); + int _Video_SetupBanks( bool bBank2 ); bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset); bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset); diff --git a/source/YamlHelper.cpp b/source/YamlHelper.cpp new file mode 100644 index 00000000..883e5982 --- /dev/null +++ b/source/YamlHelper.cpp @@ -0,0 +1,482 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 1994-1996, Michael O'Brien +Copyright (C) 1999-2001, Oliver Schmidt +Copyright (C) 2002-2005, Tom Charlesworth +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "Log.h" +#include "YamlHelper.h" + +int YamlHelper::InitParser(const char* pPathname) +{ + m_hFile = fopen(pPathname, "r"); + if (m_hFile == NULL) + { + return 0; + } + + if (!yaml_parser_initialize(&m_parser)) + { + return 0; + } + + yaml_parser_set_input_file(&m_parser, m_hFile); + + return 1; +} + +void YamlHelper::FinaliseParser(void) +{ + if (m_hFile) + fclose(m_hFile); + + m_hFile = NULL; +} + +void YamlHelper::GetNextEvent(bool bInMap /*= false*/) +{ + if (!yaml_parser_parse(&m_parser, &m_newEvent)) + { + //printf("Parser error %d\n", m_parser.error); + throw std::string("Parser error"); + } +} + +int YamlHelper::GetScalar(std::string& scalar) +{ + int res = 1; + bool bDone = false; + + while (!bDone) + { + GetNextEvent(); + + switch(m_newEvent.type) + { + case YAML_SCALAR_EVENT: + scalar = m_scalarName = (const char*)m_newEvent.data.scalar.value; + res = 1; + bDone = true; + break; + case YAML_SEQUENCE_END_EVENT: + res = 0; + bDone = true; + break; + case YAML_MAPPING_END_EVENT: + res = 0; + bDone = true; + break; + case YAML_STREAM_END_EVENT: + res = 0; + bDone = true; + break; + } + } + + return res; +} + +void YamlHelper::GetMapStartEvent(void) +{ + GetNextEvent(); + + if (m_newEvent.type != YAML_MAPPING_START_EVENT) + { + //printf("Unexpected yaml event (%d)\n", m_newEvent.type); + throw std::string("Unexpected yaml event"); + } +} + +int YamlHelper::ParseMap(MapYaml& mapYaml) +{ + mapYaml.clear(); + + const char*& pValue = (const char*&) m_newEvent.data.scalar.value; + + bool bKey = true; + char* pKey = NULL; + int res = 1; + bool bDone = false; + + while (!bDone) + { + GetNextEvent(true); + + switch(m_newEvent.type) + { + case YAML_STREAM_END_EVENT: + res = 0; + bDone = true; + break; + case YAML_MAPPING_START_EVENT: + { + MapValue mapValue; + mapValue.value = ""; + mapValue.subMap = new MapYaml; + mapYaml[std::string(pKey)] = mapValue; + res = ParseMap(*mapValue.subMap); + if (!res) + throw std::string("ParseMap: premature end of file during map parsing"); + bKey = true; // possibly more key,value pairs in this map + } + break; + case YAML_MAPPING_END_EVENT: + bDone = true; + break; + case YAML_SCALAR_EVENT: + if (bKey) + { + pKey = _strdup(pValue); + } + else + { + MapValue mapValue; + mapValue.value = pValue; + mapValue.subMap = NULL; + mapYaml[std::string(pKey)] = mapValue; + delete [] pKey; pKey = NULL; + } + + bKey = bKey ? false : true; + break; + case YAML_SEQUENCE_START_EVENT: + case YAML_SEQUENCE_END_EVENT: + throw std::string("ParseMap: Sequence event unsupported"); + } + } + + if (pKey) + delete [] pKey; + + return res; +} + +std::string YamlHelper::GetMapValue(MapYaml& mapYaml, const std::string key, bool& bFound) +{ + MapYaml::const_iterator iter = mapYaml.find(key); + if (iter == mapYaml.end() || iter->second.subMap != NULL) + { + bFound = false; // not found + return ""; + } + + std::string value = iter->second.value; + + mapYaml.erase(iter); + + bFound = true; + return value; +} + +bool YamlHelper::GetSubMap(MapYaml** mapYaml, const std::string key) +{ + MapYaml::const_iterator iter = (*mapYaml)->find(key); + if (iter == (*mapYaml)->end() || iter->second.subMap == NULL) + { + return false; // not found + } + + *mapYaml = iter->second.subMap; + return true; +} + +void YamlHelper::GetMapRemainder(std::string& mapName, MapYaml& mapYaml) +{ + for (MapYaml::iterator iter = mapYaml.begin(); iter != mapYaml.end(); ++iter) + { + if (iter->second.subMap) + { + std::string subMapName(iter->first); + GetMapRemainder(subMapName, *iter->second.subMap); + delete iter->second.subMap; + } + else + { + const char* pKey = iter->first.c_str(); + LogOutput("%s: Unknown key (%s)\n", mapName.c_str(), pKey); + LogFileOutput("%s: Unknown key (%s)\n", mapName.c_str(), pKey); + } + } + + mapYaml.clear(); +} + +// + +void YamlHelper::MakeAsciiToHexTable(void) +{ + memset(m_AsciiToHex, -1, sizeof(m_AsciiToHex)); + + for (int i = '0'; i<= '9'; i++) + m_AsciiToHex[i] = i - '0'; + + for (int i = 'A'; i<= 'F'; i++) + m_AsciiToHex[i] = i - 'A' + 0xA; + + for (int i = 'a'; i<= 'f'; i++) + m_AsciiToHex[i] = i - 'a' + 0xA; +} + +void YamlHelper::LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize) +{ + for (MapYaml::iterator it = mapYaml.begin(); it != mapYaml.end(); ++it) + { + const char* pKey = it->first.c_str(); + UINT addr = strtoul(pKey, NULL, 16); + if (addr >= kAddrSpaceSize) + throw std::string("Memory: line address too big: " + it->first); + + LPBYTE pDst = (LPBYTE) (pMemBase + addr); + const LPBYTE pDstEnd = (LPBYTE) (pMemBase + kAddrSpaceSize); + + if (it->second.subMap) + throw std::string("Memory: unexpected sub-map"); + + const char* pValue = it->second.value.c_str(); + size_t len = strlen(pValue); + if (len & 1) + throw std::string("Memory: hex data must be an even number of nibbles on line address: " + it->first); + + for (UINT i = 0; i= pDstEnd) + throw std::string("Memory: hex data overflowed address space on line address: " + it->first); + + BYTE ah = m_AsciiToHex[ (BYTE)(*pValue++) ]; + BYTE al = m_AsciiToHex[ (BYTE)(*pValue++) ]; + if ((ah | al) & 0x80) + throw std::string("Memory: hex data contains illegal character on line address: " + it->first); + + *pDst++ = (ah<<4) | al; + } + } + + mapYaml.clear(); +} + +//------------------------------------- + +INT YamlLoadHelper::LoadInt(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "") + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return strtol(value.c_str(), NULL, 0); +} + +UINT YamlLoadHelper::LoadUint(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "") + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return strtoul(value.c_str(), NULL, 0); +} + +UINT64 YamlLoadHelper::LoadUint64(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "") + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return _strtoui64(value.c_str(), NULL, 0); +} + +bool YamlLoadHelper::LoadBool(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "true") + return true; + else if (value == "false") + return false; + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); +} + +std::string YamlLoadHelper::LoadString_NoThrow(const std::string& key, bool& bFound) +{ + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + return value; +} + +std::string YamlLoadHelper::LoadString(const std::string& key) +{ + bool bFound; + std::string value = LoadString_NoThrow(key, bFound); + if (!bFound) + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return value; +} + +void YamlLoadHelper::LoadMemory(const LPBYTE pMemBase, const size_t size) +{ + m_yamlHelper.LoadMemory(*m_pMapYaml, pMemBase, size); +} + +//------------------------------------- + +void YamlSaveHelper::Save(const char* format, ...) +{ + fwrite(m_szIndent, 1, m_indent, m_hFile); + + va_list vl; + va_start(vl, format); + vfprintf(m_hFile, format, vl); + va_end(vl); +} + +void YamlSaveHelper::SaveInt(const char* key, int value) +{ + Save("%s: %d\n", key, value); +} + +void YamlSaveHelper::SaveUint(const char* key, UINT value) +{ + Save("%s: %u\n", key, value); +} + +void YamlSaveHelper::SaveHexUint4(const char* key, UINT value) +{ + Save("%s: 0x%01X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint8(const char* key, UINT value) +{ + Save("%s: 0x%02X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint12(const char* key, UINT value) +{ + Save("%s: 0x%03X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint16(const char* key, UINT value) +{ + Save("%s: 0x%04X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint32(const char* key, UINT value) +{ + Save("%s: 0x%08X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint64(const char* key, UINT64 value) +{ + Save("%s: 0x%016llX\n", key, value); +} + +void YamlSaveHelper::SaveBool(const char* key, bool value) +{ + Save("%s: %s\n", key, value ? "true" : "false"); +} + +void YamlSaveHelper::SaveString(const char* key, const char* value) +{ + Save("%s: %s\n", key, (value[0] != 0) ? value : "\"\""); +} + +// Pre: uMemSize must be multiple of 8 +void YamlSaveHelper::SaveMemory(const LPBYTE pMemBase, const UINT uMemSize) +{ + if (uMemSize & 7) + throw std::string("Memory: size must be multiple of 8"); + + const UINT kIndent = m_indent; + + const UINT kStride = 64; + const char szHex[] = "0123456789ABCDEF"; + + size_t lineSize = kIndent+6+2*kStride+2; // "AAAA: 00010203...3F\n\00" = 6+ 2*64 +2 + char* const pLine = new char [lineSize]; + + for(DWORD dwOffset = 0x0000; dwOffset < uMemSize; dwOffset+=kStride) + { + char* pDst = pLine; + for (UINT i=0; i>12)&0xf ]; + *pDst++ = szHex[ (dwOffset>>8)&0xf ]; + *pDst++ = szHex[ (dwOffset>>4)&0xf ]; + *pDst++ = szHex[ dwOffset&0xf ]; + *pDst++ = ':'; + *pDst++ = ' '; + + LPBYTE pMem = pMemBase + dwOffset; + + for (UINT i=0; i= uMemSize) // Support short final line (still multiple of 8 bytes) + { + lineSize = lineSize - 2*kStride + 2*i; + break; + } + + BYTE d; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + } + + *pDst++ = '\n'; + *pDst = 0; // For debugger + + fwrite(pLine, 1, lineSize-1, m_hFile); // -1 so don't write null terminator + } + + delete [] pLine; +} + +void YamlSaveHelper::FileHdr(UINT version) +{ + fprintf(m_hFile, "%s:\n", SS_YAML_KEY_FILEHDR); + m_indent = 2; + SaveString(SS_YAML_KEY_TAG, SS_YAML_VALUE_AWSS); + SaveInt(SS_YAML_KEY_VERSION, version); +} + +void YamlSaveHelper::UnitHdr(std::string type, UINT version) +{ + fprintf(m_hFile, "\n%s:\n", SS_YAML_KEY_UNIT); + m_indent = 2; + SaveString(SS_YAML_KEY_TYPE, type.c_str()); + SaveInt(SS_YAML_KEY_VERSION, version); +} diff --git a/source/YamlHelper.h b/source/YamlHelper.h new file mode 100644 index 00000000..31e871ca --- /dev/null +++ b/source/YamlHelper.h @@ -0,0 +1,266 @@ +#pragma once + +#include "yaml.h" + +#define SS_YAML_KEY_FILEHDR "File_hdr" +#define SS_YAML_KEY_TAG "Tag" +#define SS_YAML_KEY_VERSION "Version" +#define SS_YAML_KEY_UNIT "Unit" +#define SS_YAML_KEY_TYPE "Type" +#define SS_YAML_KEY_CARD "Card" +#define SS_YAML_KEY_STATE "State" + +#define SS_YAML_VALUE_AWSS "AppleWin Save State" + +struct MapValue; +typedef std::map MapYaml; + +struct MapValue +{ + std::string value; + MapYaml* subMap; +}; + +class YamlHelper +{ +friend class YamlLoadHelper; // YamlLoadHelper can access YamlHelper's private members + +public: + YamlHelper(void) : + m_hFile(NULL) + { + MakeAsciiToHexTable(); + } + + ~YamlHelper(void) + { + if (m_hFile) + fclose(m_hFile); + } + + int InitParser(const char* pPathname); + void FinaliseParser(void); + + int GetScalar(std::string& scalar); + void GetMapStartEvent(void); + +private: + void GetNextEvent(bool bInMap = false); + int ParseMap(MapYaml& mapYaml); + std::string GetMapValue(MapYaml& mapYaml, const std::string key, bool& bFound); + void LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize); + bool GetSubMap(MapYaml** mapYaml, const std::string key); + void GetMapRemainder(std::string& mapName, MapYaml& mapYaml); + + void MakeAsciiToHexTable(void); + + yaml_parser_t m_parser; + yaml_event_t m_newEvent; + + std::string m_scalarName; + + FILE* m_hFile; + char m_AsciiToHex[256]; + + MapYaml m_mapYaml; +}; + +// ----- + +class YamlLoadHelper +{ +public: + YamlLoadHelper(YamlHelper& yamlHelper) + : m_yamlHelper(yamlHelper), + m_pMapYaml(&yamlHelper.m_mapYaml), + m_bIteratingOverMap(false), + m_bDoGetMapRemainder(true), + m_topLevelMapName(yamlHelper.m_scalarName), + m_currentMapName(m_topLevelMapName) + { + if (!m_yamlHelper.ParseMap(yamlHelper.m_mapYaml)) + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Failed to parse map"); + } + } + + ~YamlLoadHelper(void) + { + if (m_bDoGetMapRemainder) + m_yamlHelper.GetMapRemainder(m_topLevelMapName, m_yamlHelper.m_mapYaml); + } + + INT LoadInt(const std::string key); + UINT LoadUint(const std::string key); + UINT64 LoadUint64(const std::string key); + bool LoadBool(const std::string key); + std::string LoadString_NoThrow(const std::string& key, bool& bFound); + std::string LoadString(const std::string& key); + void LoadMemory(const LPBYTE pMemBase, const size_t size); + + bool GetSubMap(const std::string key) + { + YamlStackItem item = {m_pMapYaml, m_currentMapName}; + m_stackMap.push(item); + bool res = m_yamlHelper.GetSubMap(&m_pMapYaml, key); + if (!res) + m_stackMap.pop(); + else + m_currentMapName = key; + return res; + } + + void PopMap(void) + { + if (m_stackMap.empty()) + return; + + YamlStackItem item = m_stackMap.top(); + m_stackMap.pop(); + + m_pMapYaml = item.pMapYaml; + m_currentMapName = item.mapName; + } + + std::string GetMapNextSlotNumber(void) + { + if (!m_bIteratingOverMap) + { + m_iter = m_pMapYaml->begin(); + m_bIteratingOverMap = true; + } + + if (m_iter == m_pMapYaml->end()) + { + m_bIteratingOverMap = false; + return ""; + } + + std::string scalar = m_iter->first; + ++m_iter; + return scalar; + } + +private: + YamlHelper& m_yamlHelper; + MapYaml* m_pMapYaml; + bool m_bDoGetMapRemainder; + + struct YamlStackItem + { + MapYaml* pMapYaml; + std::string mapName; + }; + std::stack m_stackMap; + + std::string m_topLevelMapName; + std::string m_currentMapName; + + bool m_bIteratingOverMap; + MapYaml::iterator m_iter; +}; + +// ----- + +class YamlSaveHelper +{ +public: + YamlSaveHelper(std::string pathname) : + m_hFile(NULL), + m_indent(0) + { + m_hFile = fopen(pathname.c_str(), "wt"); + + // todo: handle ERROR_ALREADY_EXISTS - ask if user wants to replace existing file + // - at this point any old file will have been truncated to zero + + if(m_hFile == NULL) + throw std::string("Save error"); + + _tzset(); + time_t ltime; + time(<ime); + char timebuf[26]; + errno_t err = ctime_s(timebuf, sizeof(timebuf), <ime); // includes newline at end of string + fprintf(m_hFile, "# Date-stamp: %s\n", err == 0 ? timebuf : "Error: Datestamp\n\n"); + + fprintf(m_hFile, "---\n"); + + // + + memset(m_szIndent, ' ', kMaxIndent); + } + + ~YamlSaveHelper() + { + if (m_hFile) + { + fprintf(m_hFile, "...\n"); + fclose(m_hFile); + } + } + + void Save(const char* format, ...); + + void SaveInt(const char* key, int value); + void SaveUint(const char* key, UINT value); + void SaveHexUint4(const char* key, UINT value); + void SaveHexUint8(const char* key, UINT value); + void SaveHexUint12(const char* key, UINT value); + void SaveHexUint16(const char* key, UINT value); + void SaveHexUint32(const char* key, UINT value); + void SaveHexUint64(const char* key, UINT64 value); + void SaveBool(const char* key, bool value); + void SaveString(const char* key, const char* value); + void SaveMemory(const LPBYTE pMemBase, const UINT uMemSize); + + class Label + { + public: + Label(YamlSaveHelper& rYamlSaveHelper, const char* format, ...) : + yamlSaveHelper(rYamlSaveHelper) + { + fwrite(yamlSaveHelper.m_szIndent, 1, yamlSaveHelper.m_indent, yamlSaveHelper.m_hFile); + + va_list vl; + va_start(vl, format); + vfprintf(yamlSaveHelper.m_hFile, format, vl); + va_end(vl); + + yamlSaveHelper.m_indent += 2; + _ASSERT(yamlSaveHelper.m_indent < yamlSaveHelper.kMaxIndent); + } + + ~Label(void) + { + yamlSaveHelper.m_indent -= 2; + _ASSERT(yamlSaveHelper.m_indent >= 0); + } + + YamlSaveHelper& yamlSaveHelper; + }; + + class Slot : public Label + { + public: + Slot(YamlSaveHelper& rYamlSaveHelper, std::string type, UINT slot, UINT version) : + Label(rYamlSaveHelper, "%d:\n", slot) + { + rYamlSaveHelper.Save("%s: %s\n", SS_YAML_KEY_CARD, type.c_str()); + rYamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_VERSION, version); + } + + ~Slot(void) {} + }; + + void FileHdr(UINT version); + void UnitHdr(std::string type, UINT version); + +private: + FILE* m_hFile; + + int m_indent; + static const UINT kMaxIndent = 50*2; + char m_szIndent[kMaxIndent]; +}; diff --git a/source/Z80VICE/z80.cpp b/source/Z80VICE/z80.cpp index fe8cdfe6..7738cb40 100644 --- a/source/Z80VICE/z80.cpp +++ b/source/Z80VICE/z80.cpp @@ -29,6 +29,7 @@ #include "..\AppleWin.h" #include "..\CPU.h" #include "..\Memory.h" +#include "..\YamlHelper.h" #undef IN // Defined in windef.h @@ -86,16 +87,20 @@ static BYTE reg_f2 = 0; static BYTE reg_h2 = 0; static BYTE reg_l2 = 0; +#if 0 // [AppleWin-TC] Not used static int dma_request = 0; +#endif static BYTE *z80_bank_base; static int z80_bank_limit; +#if 0 // [AppleWin-TC] Not used void z80_trigger_dma(void) { dma_request = 1; } +#endif void z80_reset(void) { @@ -162,11 +167,11 @@ void z80_reset(void) /* ------------------------------------------------------------------------- */ +#if 0 // [AppleWin-TC] static unsigned int z80_last_opcode_info; #define LAST_OPCODE_INFO z80_last_opcode_info -#if 0 // [AppleWin-TC] /* Remember the number of the last opcode. By default, the opcode does not delay interrupt and does not change the I flag. */ #define SET_LAST_OPCODE(x) \ @@ -463,6 +468,9 @@ static void export_registers(void) /* ------------------------------------------------------------------------- */ +// [AppleWin-TC] Z80 IRQs not supported + +#if 0 /* Interrupt handling. */ #define DO_INTERRUPT(int_kind) \ @@ -533,6 +541,7 @@ static void export_registers(void) } \ } \ } while (0) +#endif /* ------------------------------------------------------------------------- */ @@ -6330,7 +6339,7 @@ DWORD z80_mainloop(ULONG uTotalCycles, ULONG uExecutedCycles) //cpu_int_status->num_dma_per_opcode = 0; // [AppleWin-TC] Not used - if (g_ActiveCPU != CPU_Z80) // [AppleWin-TC] + if (GetActiveCpu() != CPU_Z80) // [AppleWin-TC] break; //} while (!dma_request); @@ -6422,3 +6431,139 @@ void z80_WRMEM(WORD Addr, BYTE Value) } CpuWrite( addr, Value, ConvertZ80TStatesTo6502Cycles(maincpu_clk) ); } + +//=========================================================================== + +#define SS_YAML_VALUE_CARD_Z80 "Z80" + +#define SS_YAML_KEY_REGA "A" +#define SS_YAML_KEY_REGB "B" +#define SS_YAML_KEY_REGC "C" +#define SS_YAML_KEY_REGD "D" +#define SS_YAML_KEY_REGE "E" +#define SS_YAML_KEY_REGF "F" +#define SS_YAML_KEY_REGH "H" +#define SS_YAML_KEY_REGL "L" +#define SS_YAML_KEY_REGIX "IX" +#define SS_YAML_KEY_REGIY "IY" +#define SS_YAML_KEY_REGSP "SP" +#define SS_YAML_KEY_REGPC "PC" +#define SS_YAML_KEY_REGI "I" +#define SS_YAML_KEY_REGR "R" +#define SS_YAML_KEY_IFF1 "IFF1" +#define SS_YAML_KEY_IFF2 "IFF2" +#define SS_YAML_KEY_IM_MODE "IM Mode" +#define SS_YAML_KEY_REGA2 "A'" +#define SS_YAML_KEY_REGB2 "B'" +#define SS_YAML_KEY_REGC2 "C'" +#define SS_YAML_KEY_REGD2 "D'" +#define SS_YAML_KEY_REGE2 "E'" +#define SS_YAML_KEY_REGF2 "F'" +#define SS_YAML_KEY_REGH2 "H'" +#define SS_YAML_KEY_REGL2 "L'" +#define SS_YAML_KEY_ACTIVE "Active" + +std::string Z80_GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_Z80); + return name; +} + +void Z80_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot) +{ + YamlSaveHelper::Slot slot(yamlSaveHelper, Z80_GetSnapshotCardName(), uSlot, 1); // fixme: object should know its slot + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + // SoftCard SW & HW details: http://apple2info.net/images/f/f0/SC-SWHW.pdf + // . SoftCard uses the Apple II's DMA circuit to pause the 6502 (no CLK to 6502) + // . But: "In Apple II DMA, the 6502 CPU will die after approximately 15 clocks because it depends on the clock to refresh its internal registers." + // ref: Apple Tech Note: https://archive.org/stream/IIe_2523004_RDY_Line/IIe_2523004_RDY_Line_djvu.txt + // NB. Not for 65C02 which is a static processor. + // . SoftCard controls the 6502's RDY line to periodically allow only 1 memory fetch by 6502 (ie. the opcode fetch) + // + // So save ActiveCPU to SS_CARD_Z80 (so RDY is like IRQ & NMI signals, ie. saved struct of the producer's card) + // + // NB. Save-state only occurs when message pump runs: + // . ie. at end of 1ms emulation burst + // Either 6502 or Z80 could be active. + // + + yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_ACTIVE, GetActiveCpu() == CPU_Z80 ? 1 : 0); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGA, reg_a); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGB, reg_b); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGC, reg_c); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGD, reg_d); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGE, reg_e); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGF, reg_f); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGH, reg_h); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGL, reg_l); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGIX, ((USHORT)reg_ixh<<8)|(USHORT)reg_ixl); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGIY, ((USHORT)reg_iyh<<8)|(USHORT)reg_iyl); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGSP, reg_sp); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGPC, (USHORT)z80_reg_pc); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGI, reg_i); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGR, reg_r); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IFF1, iff1); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IFF2, iff2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IM_MODE, im_mode); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGA2, reg_a2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGB2, reg_b2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGC2, reg_c2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGD2, reg_d2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGE2, reg_e2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGF2, reg_f2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGH2, reg_h2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGL2, reg_l2); +} + +bool Z80_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uSlot, UINT version) +{ + if (uSlot != 4 && uSlot != 5) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + reg_a = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGA); + reg_b = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGB); + reg_c = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGC); + reg_d = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGD); + reg_e = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGE); + reg_f = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGF); + reg_h = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGH); + reg_l = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGL); + USHORT IX = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGIX); + reg_ixh = IX >> 8; + reg_ixl = IX & 0xFF; + USHORT IY = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGIY); + reg_iyh = IY >> 8; + reg_iyl = IY & 0xFF; + reg_sp = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGSP); + z80_reg_pc = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGPC); + reg_i = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGI); + reg_r = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGR); + + iff1 = yamlLoadHelper.LoadUint(SS_YAML_KEY_IFF1); + iff2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_IFF2); + im_mode = yamlLoadHelper.LoadUint(SS_YAML_KEY_IM_MODE); + + reg_a2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGA2); + reg_b2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGB2); + reg_c2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGC2); + reg_d2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGD2); + reg_e2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGE2); + reg_f2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGF2); + reg_h2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGH2); + reg_l2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGL2); + + export_registers(); + + if ( yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVE) ) + SetActiveCpu(CPU_Z80); // Support MS SoftCard in multiple slots (only one Z80 can be active at any one time) + + return true; +} diff --git a/source/Z80VICE/z80regs.h b/source/Z80VICE/z80regs.h index 025d08fc..54c59e81 100644 --- a/source/Z80VICE/z80regs.h +++ b/source/Z80VICE/z80regs.h @@ -46,6 +46,7 @@ typedef struct z80_regs_s { WORD reg_hl2; } z80_regs_t; +#if 0 // [AppleWin-TC]: unused, so comment out #define Z80_REGS_GET_AF(reg_ptr) ((reg_ptr)->reg_af) #define Z80_REGS_GET_BC(reg_ptr) ((reg_ptr)->reg_bc) #define Z80_REGS_GET_DE(reg_ptr) ((reg_ptr)->reg_de) @@ -75,6 +76,7 @@ typedef struct z80_regs_s { #define Z80_REGS_SET_BC2(reg_ptr, val) ((reg_ptr)->reg_bc2 = (val)) #define Z80_REGS_SET_DE2(reg_ptr, val) ((reg_ptr)->reg_de2 = (val)) #define Z80_REGS_SET_HL2(reg_ptr, val) ((reg_ptr)->reg_hl2 = (val)) +#endif #endif diff --git a/source/z80emu.cpp b/source/z80emu.cpp index 932711e3..01542099 100644 --- a/source/z80emu.cpp +++ b/source/z80emu.cpp @@ -16,6 +16,7 @@ #include "StdAfx.h" #include "AppleWin.h" +#include "CPU.h" #include "Memory.h" #include "z80emu.h" @@ -30,7 +31,7 @@ BYTE __stdcall CPMZ80_IONull(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULON BYTE __stdcall CPMZ80_IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft) { if ((uAddr & 0xFF00) == (0xC000 + (g_uCPMZ80Slot << 8))) - g_ActiveCPU = (g_ActiveCPU == CPU_6502) ? CPU_Z80 : CPU_6502; + SetActiveCpu( GetActiveCpu() == CPU_Z80 ? GetMainCpu() : CPU_Z80 ); return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft); } diff --git a/source/z80emu.h b/source/z80emu.h index 18d20504..3b256f0a 100644 --- a/source/z80emu.h +++ b/source/z80emu.h @@ -14,3 +14,8 @@ // Protótipos void ConfigureSoftcard(LPBYTE pCxRomPeripheral, UINT uSlot); + +// NB. These are in z80.cpp: +std::string Z80_GetSnapshotCardName(void); +void Z80_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); +bool Z80_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uSlot, UINT version); From 08a9f8798ebedda5b289721cc7e388c510f2ed06 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 22 Mar 2016 23:34:35 +0000 Subject: [PATCH 102/121] Fix invalid literal error for VS2015 --- source/MouseInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MouseInterface.cpp b/source/MouseInterface.cpp index 34b25788..9be5d279 100644 --- a/source/MouseInterface.cpp +++ b/source/MouseInterface.cpp @@ -731,7 +731,7 @@ bool CMouseInterface::LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT sl m_by6821A = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821A); if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_BUFF)) - throw std::string("Card: Expected key: "SS_YAML_KEY_BUFF); + throw std::string("Card: Expected key: " SS_YAML_KEY_BUFF); yamlLoadHelper.LoadMemory(m_byBuff, sizeof(m_byBuff)); yamlLoadHelper.PopMap(); From 99219a71ecb8e9760ec5ea63bc2040099a3fd684 Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 24 Mar 2016 22:25:35 +0000 Subject: [PATCH 103/121] Add VS2015 proj files & fix for building under VS2015 in Release --- .gitignore | 1 + AppleWinExpress2015.sln | 74 ++ AppleWinExpress2015.vcxproj | 462 ++++++++++++ AppleWinExpress2015.vcxproj.filters | 675 ++++++++++++++++++ libyaml/win32/yaml2015.vcxproj | 100 +++ libyaml/win32/yaml2015.vcxproj.filters | 54 ++ source/Debugger/Debugger_Color.cpp | 2 +- source/Debugger/Debugger_Color.h | 2 +- test/TestCPU6502/TestCPU6502-vs2015.vcxproj | 89 +++ .../TestCPU6502-vs2015.vcxproj.filters | 22 + zip_lib/zip_lib2015.vcxproj | 96 +++ zip_lib/zip_lib2015.vcxproj.filters | 45 ++ zlib/zlib-Express2015.vcxproj | 106 +++ zlib/zlib-Express2015.vcxproj.filters | 81 +++ 14 files changed, 1807 insertions(+), 2 deletions(-) create mode 100644 AppleWinExpress2015.sln create mode 100644 AppleWinExpress2015.vcxproj create mode 100644 AppleWinExpress2015.vcxproj.filters create mode 100644 libyaml/win32/yaml2015.vcxproj create mode 100644 libyaml/win32/yaml2015.vcxproj.filters create mode 100644 test/TestCPU6502/TestCPU6502-vs2015.vcxproj create mode 100644 test/TestCPU6502/TestCPU6502-vs2015.vcxproj.filters create mode 100644 zip_lib/zip_lib2015.vcxproj create mode 100644 zip_lib/zip_lib2015.vcxproj.filters create mode 100644 zlib/zlib-Express2015.vcxproj create mode 100644 zlib/zlib-Express2015.vcxproj.filters diff --git a/.gitignore b/.gitignore index 5b4334f5..03c74460 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.suo *.user *.sln.docstates +*.VC.opendb # Build results [Dd]ebug/ diff --git a/AppleWinExpress2015.sln b/AppleWinExpress2015.sln new file mode 100644 index 00000000..ab925ed9 --- /dev/null +++ b/AppleWinExpress2015.sln @@ -0,0 +1,74 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2015.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" + ProjectSection(ProjectDependencies) = postProject + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} = {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} + {0212E0DF-06DA-4080-BD1D-F3B01599F70F} = {0212E0DF-06DA-4080-BD1D-F3B01599F70F} + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} = {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip_lib", "zip_lib\zip_lib2015.vcxproj", "{509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib-Express2015.vcxproj", "{9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2015.vcxproj", "{0212E0DF-06DA-4080-BD1D-F3B01599F70F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCPU6502", "test\TestCPU6502\TestCPU6502-vs2015.vcxproj", "{CF5A49BF-62A5-41BB-B10C-F34D556A7A45}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug NoDX|Win32 = Debug NoDX|Win32 + Debug|Win32 = Debug|Win32 + Release NoDX|Win32 = Release NoDX|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug NoDX|Win32.ActiveCfg = Debug NoDX|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug NoDX|Win32.Build.0 = Debug NoDX|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug|Win32.ActiveCfg = Debug|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug|Win32.Build.0 = Debug|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release NoDX|Win32.ActiveCfg = Release NoDX|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release NoDX|Win32.Build.0 = Release NoDX|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release|Win32.ActiveCfg = Release|Win32 + {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release|Win32.Build.0 = Release|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug|Win32.ActiveCfg = Debug|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug|Win32.Build.0 = Debug|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release NoDX|Win32.Build.0 = Release|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release|Win32.ActiveCfg = Release|Win32 + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release|Win32.Build.0 = Release|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug|Win32.ActiveCfg = Debug|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug|Win32.Build.0 = Debug|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release NoDX|Win32.Build.0 = Release|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release|Win32.ActiveCfg = Release|Win32 + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release|Win32.Build.0 = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug|Win32.ActiveCfg = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Debug|Win32.Build.0 = Debug|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release NoDX|Win32.Build.0 = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release|Win32.ActiveCfg = Release|Win32 + {0212E0DF-06DA-4080-BD1D-F3B01599F70F}.Release|Win32.Build.0 = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Debug|Win32.Build.0 = Debug|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.Build.0 = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.ActiveCfg = Release|Win32 + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/AppleWinExpress2015.vcxproj b/AppleWinExpress2015.vcxproj new file mode 100644 index 00000000..e9f9a8d2 --- /dev/null +++ b/AppleWinExpress2015.vcxproj @@ -0,0 +1,462 @@ + + + + + Debug NoDX + Win32 + + + Debug + Win32 + + + Release NoDX + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + {509739e7-0af3-4c09-a1a9-f0b1bc31b39d} + + + {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} + + + {0212e0df-06da-4080-bd1d-f3b01599f70f} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0A960136-A00A-4D4B-805F-664D9950D2CA} + Win32Proj + AppleWinExpress2013 + AppleWin + + + + Application + true + v140 + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + false + MultiByte + + + Application + false + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Windows + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + + echo Performing unit-test: TestCPU6502 +.\Debug\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Windows + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + + echo Performing unit-test: TestCPU6502 +.\Debug\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) + MultiThreaded + Speed + + + Windows + true + true + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + + echo Performing unit-test: TestCPU6502 +.\Release\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) + MultiThreaded + Speed + + + Windows + true + true + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + + echo Performing unit-test: TestCPU6502 +.\Release\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + + + + + + \ No newline at end of file diff --git a/AppleWinExpress2015.vcxproj.filters b/AppleWinExpress2015.vcxproj.filters new file mode 100644 index 00000000..c9b778eb --- /dev/null +++ b/AppleWinExpress2015.vcxproj.filters @@ -0,0 +1,675 @@ + + + + + Source Files + + + Source Files\Emulator + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\CPU + + + Source Files\Z80VICE + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Video + + + Source Files\Disk + + + Source Files\Disk + + + Source Files\Disk + + + Source Files\Disk + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files + + + Source Files\Emulator + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Video + + + Source Files\Z80VICE + + + Source Files\Z80VICE + + + Source Files\Emulator + + + Source Files\Debugger + + + Source Files\Video + + + Source Files\Model + + + Source Files\Emulator + + + Source Files\Emulator + + + + + Source Files + + + Source Files\CommonVICE + + + Source Files\CommonVICE + + + Source Files\Emulator + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\_Headers + + + Source Files\Configuration + + + Source Files\CPU + + + Source Files\CPU + + + Source Files\CPU + + + Source Files\CPU + + + Source Files\Z80VICE + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Video + + + Source Files\Disk + + + Source Files\Disk + + + Source Files\Disk + + + Source Files\Disk + + + Source Files\CommonVICE + + + Source Files\CommonVICE + + + Source Files\CommonVICE + + + Source Files\Uthernet + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Configuration + + + Source Files\Emulator + + + Source Files\_Headers + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\_Headers + + + Source Files + + + Source Files\Emulator + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Uthernet + + + Source Files\Video + + + Resource Files + + + Source Files\Z80VICE + + + Source Files\Z80VICE + + + Source Files\Z80VICE + + + Source Files\Emulator + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Debugger + + + Source Files\Disk + + + Source Files\Video + + + Source Files\Model + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\_Headers + + + Source Files\_Headers + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Source Files\CPU + + + Source Files\CPU + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Docs + + + Docs + + + Docs + + + Docs + + + Docs + + + Docs + + + + + + {88e8853b-7cec-4a16-9dd9-5a2b96bf3c8b} + + + {c8f186d6-7988-4d45-87c5-d9ea62c75953} + + + {fa2685fb-1686-4525-9ac1-bcca3310c473} + + + {8578fca7-e2e4-488a-995e-bc1fd1c4286e} + + + {dd629946-2094-409f-83a7-791ceff4bec2} + + + {30a9b810-6ebd-4505-a45d-6ed212c3ba5a} + + + {66471c82-8e9b-4c65-9514-600cfbd2d4c1} + + + {6a0a220b-e39c-486c-9f04-828b4ba6ace2} + + + {6b2abcf9-39f7-4b19-ab2a-bab66c3ed4bd} + + + {ea6eab89-9568-4f06-99e7-5d1fe99a8578} + + + {8ea2437f-ac40-4ef6-9b68-7f5244480457} + + + {f535a998-5bc0-43a6-a96e-65918c92b8fc} + + + {b5c6889e-727d-4339-96c8-e4284e1d6e0f} + + + {15b450e4-f89f-4d80-9c44-48b32f33f3e3} + + + + + Resource Files + + + \ No newline at end of file diff --git a/libyaml/win32/yaml2015.vcxproj b/libyaml/win32/yaml2015.vcxproj new file mode 100644 index 00000000..bfc7da41 --- /dev/null +++ b/libyaml/win32/yaml2015.vcxproj @@ -0,0 +1,100 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + {0212E0DF-06DA-4080-BD1D-F3B01599F70F} + Win32Proj + yaml2013 + yaml + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;YAML_DECLARE_STATIC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + .;../include + MultiThreadedDebug + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;YAML_DECLARE_STATIC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + .;../include + MultiThreaded + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/libyaml/win32/yaml2015.vcxproj.filters b/libyaml/win32/yaml2015.vcxproj.filters new file mode 100644 index 00000000..2446a756 --- /dev/null +++ b/libyaml/win32/yaml2015.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/source/Debugger/Debugger_Color.cpp b/source/Debugger/Debugger_Color.cpp index 91baba7e..dc737b09 100644 --- a/source/Debugger/Debugger_Color.cpp +++ b/source/Debugger/Debugger_Color.cpp @@ -135,7 +135,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //=========================================================================== -inline COLORREF DebuggerGetColor( int iColor ) +COLORREF DebuggerGetColor( int iColor ) { COLORREF nColor = RGB(0,255,255); // 0xFFFF00; // Hot Pink! -- so we notice errors. Not that there is anything wrong with pink... diff --git a/source/Debugger/Debugger_Color.h b/source/Debugger/Debugger_Color.h index e098add4..f20bea05 100644 --- a/source/Debugger/Debugger_Color.h +++ b/source/Debugger/Debugger_Color.h @@ -130,5 +130,5 @@ extern int g_aColorIndex[ NUM_DEBUG_COLORS ]; // Color - inline COLORREF DebuggerGetColor( int iColor ); + COLORREF DebuggerGetColor( int iColor ); bool DebuggerSetColor ( const int iScheme, const int iColor, const COLORREF nColor ); diff --git a/test/TestCPU6502/TestCPU6502-vs2015.vcxproj b/test/TestCPU6502/TestCPU6502-vs2015.vcxproj new file mode 100644 index 00000000..26e0fa2b --- /dev/null +++ b/test/TestCPU6502/TestCPU6502-vs2015.vcxproj @@ -0,0 +1,89 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} + Win32Proj + TestCPU6502vs2013 + TestCPU6502 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/test/TestCPU6502/TestCPU6502-vs2015.vcxproj.filters b/test/TestCPU6502/TestCPU6502-vs2015.vcxproj.filters new file mode 100644 index 00000000..71e4100b --- /dev/null +++ b/test/TestCPU6502/TestCPU6502-vs2015.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/zip_lib/zip_lib2015.vcxproj b/zip_lib/zip_lib2015.vcxproj new file mode 100644 index 00000000..e4fb936c --- /dev/null +++ b/zip_lib/zip_lib2015.vcxproj @@ -0,0 +1,96 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} + Win32Proj + zip_lib + zip_lib + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + NotUsing + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\zlib;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\zlib;%(AdditionalIncludeDirectories) + MultiThreaded + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/zip_lib/zip_lib2015.vcxproj.filters b/zip_lib/zip_lib2015.vcxproj.filters new file mode 100644 index 00000000..a95759e4 --- /dev/null +++ b/zip_lib/zip_lib2015.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + {96af84b6-da06-44fd-be50-1191b41ce4a9} + + + \ No newline at end of file diff --git a/zlib/zlib-Express2015.vcxproj b/zlib/zlib-Express2015.vcxproj new file mode 100644 index 00000000..a35e3687 --- /dev/null +++ b/zlib/zlib-Express2015.vcxproj @@ -0,0 +1,106 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} + Win32Proj + zlib + zlib + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + NotUsing + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/zlib/zlib-Express2015.vcxproj.filters b/zlib/zlib-Express2015.vcxproj.filters new file mode 100644 index 00000000..36bab27a --- /dev/null +++ b/zlib/zlib-Express2015.vcxproj.filters @@ -0,0 +1,81 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + {52e6f426-af67-45d0-9d29-bd5a2351cd85} + + + \ No newline at end of file From ad55b0f1369be7edd82f7d91244ad985f8211275 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 27 Mar 2016 23:25:28 +0100 Subject: [PATCH 104/121] Fix for when VideoMode = {Text_Optimized | TV} in 50% scanline mode: . RGB arithmetic could underflow . Now clamp to zero (ToDo: consider using SIMD) --- source/NTSC.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 44bcc42c..eea55f92 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -573,7 +573,16 @@ inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTa const uint32_t color0 = getScanlineColor( signal, pTable ); const uint32_t color2 = *pLine2Address; - const uint32_t color1 = color0 - ((color2 & 0x00fcfcfc) >> 2); // BUG? color0 - color0? not color0-color2? +// const uint32_t color1 = color0 - ((color2 & 0x00fcfcfc) >> 2); // BUG? color0 - color0? not color0-color2? + // TC: The above operation "color0 - ((color2 & 0x00fcfcfc) >> 2)" causes underflow, so I've recoded to clamp on underflow: + { + int r=(color0>>16)&0xff, g=(color0>>8)&0xff, b=color0&0xff; + uint32_t color2_prime = (color2 & 0x00fcfcfc) >> 2; + r -= (color2_prime>>16)&0xff; if (r<0) r=0; // clamp to 0 on underflow + g -= (color2_prime>>8)&0xff; if (g<0) g=0; // clamp to 0 on underflow + b -= (color2_prime)&0xff; if (b<0) b=0; // clamp to 0 on underflow + const uint32_t color1 = (r<<16)|(g<<8)|(b); + } /* */ *pLine1Address = color1 | ALPHA32_MASK; /* */ *pLine0Address = color0; From 80ad4df40979f331f197625ec107515f1b653238 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 28 Mar 2016 18:02:08 +0100 Subject: [PATCH 105/121] Fix scoping of variable --- source/NTSC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index eea55f92..85747027 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -575,13 +575,14 @@ inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTa const uint32_t color2 = *pLine2Address; // const uint32_t color1 = color0 - ((color2 & 0x00fcfcfc) >> 2); // BUG? color0 - color0? not color0-color2? // TC: The above operation "color0 - ((color2 & 0x00fcfcfc) >> 2)" causes underflow, so I've recoded to clamp on underflow: + uint32_t color1; { int r=(color0>>16)&0xff, g=(color0>>8)&0xff, b=color0&0xff; uint32_t color2_prime = (color2 & 0x00fcfcfc) >> 2; r -= (color2_prime>>16)&0xff; if (r<0) r=0; // clamp to 0 on underflow g -= (color2_prime>>8)&0xff; if (g<0) g=0; // clamp to 0 on underflow b -= (color2_prime)&0xff; if (b<0) b=0; // clamp to 0 on underflow - const uint32_t color1 = (r<<16)|(g<<8)|(b); + color1 = (r<<16)|(g<<8)|(b); } /* */ *pLine1Address = color1 | ALPHA32_MASK; From d23ae15774536bda28b6c66764edfba03fc08fd1 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 4 Apr 2016 21:05:58 +0100 Subject: [PATCH 106/121] Removed border from: . final rendered window . print-screen bmps (both sizes) Fixed full-screen so that: . all mode (RUNNING, DEBUG and LOGO) all occupy the same screen position . there's no intermediate data drawn out of position when first switching to full-screen Tested on Win7 and Win10 --- source/Debugger/Debugger_Display.cpp | 2 +- source/Frame.cpp | 18 +++----- source/Frame.h | 18 +++++--- source/Video.cpp | 67 +++++++++++++++++----------- source/Video.h | 4 +- 5 files changed, 65 insertions(+), 44 deletions(-) diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 9b854941..5ea53e6b 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -568,7 +568,7 @@ void StretchBltMemToFrameDC(void) nViewportCX, nViewportCY, // int nWidthDest, int nHeightDest, GetDebuggerMemDC(), // HDC hdcSrc, 0, 0, // int nXOriginSrc, int nYOriginSrc, - FRAMEBUFFER_W, FRAMEBUFFER_H, // int nWidthSrc, int nHeightSrc, + FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // int nWidthSrc, int nHeightSrc, SRCCOPY // DWORD dwRop ); } diff --git a/source/Frame.cpp b/source/Frame.cpp index e590b92c..95de5508 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -65,8 +65,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define MAGICY 5 // 3D border between Apple window & Title bar static const int kDEFAULT_VIEWPORT_SCALE = 2; - int g_nViewportCX = FRAMEBUFFER_W * kDEFAULT_VIEWPORT_SCALE; - int g_nViewportCY = FRAMEBUFFER_H * kDEFAULT_VIEWPORT_SCALE; + int g_nViewportCX = FRAMEBUFFER_BORDERLESS_W * kDEFAULT_VIEWPORT_SCALE; + int g_nViewportCY = FRAMEBUFFER_BORDERLESS_H * kDEFAULT_VIEWPORT_SCALE; static int g_nViewportScale = kDEFAULT_VIEWPORT_SCALE; // saved REGSAVE static int g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE; @@ -568,11 +568,7 @@ static void DrawFrameWindow () else if (g_nAppMode == MODE_DEBUG) DebugDisplay(1); else - // Win7: In fullscreen mode with 1 redraw the screen doesn't get redrawn. - // TC: 07/01/2015: Tryed with MP's double-buffered DX full-screen code, but still the same. - //VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) - //VideoRefreshScreen(0); - VideoRedrawScreen(); + VideoRedrawScreen(g_bIsFullScreen ? 1 : 0); // On WM_PAINT: delay 1 refresh before rendering full-screen if (g_bPaintingWindow) EndPaint(g_hFrameWindow,&ps); @@ -2167,8 +2163,8 @@ int SetViewportScale(int nNewScale) nNewScale = g_nMaxViewportScale; g_nViewportScale = nNewScale; - g_nViewportCX = g_nViewportScale * FRAMEBUFFER_W; - g_nViewportCY = g_nViewportScale * FRAMEBUFFER_H; + g_nViewportCX = g_nViewportScale * FRAMEBUFFER_BORDERLESS_W; + g_nViewportCY = g_nViewportScale * FRAMEBUFFER_BORDERLESS_H; return nNewScale; } @@ -2267,8 +2263,8 @@ void FrameCreateWindow(void) int nOldViewportCX = g_nViewportCX; int nOldViewportCY = g_nViewportCY; - g_nViewportCX = FRAMEBUFFER_W * 2; - g_nViewportCY = FRAMEBUFFER_H * 2; + g_nViewportCX = FRAMEBUFFER_BORDERLESS_W * 2; + g_nViewportCY = FRAMEBUFFER_BORDERLESS_H * 2; GetWidthHeight(nWidth, nHeight); // Probe with 2x dimensions g_nViewportCX = nOldViewportCX; diff --git a/source/Frame.h b/source/Frame.h index e54f4187..a0005704 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -11,14 +11,22 @@ #define VIEWPORTY 5 // 560 = Double Hi-Res - // 384 = Doule Scan Line + // 384 = Double Scan Line + #define FRAMEBUFFER_BORDERLESS_W 560 + #define FRAMEBUFFER_BORDERLESS_H 384 // NTSC_BEGIN #if 0 - #define FRAMEBUFFER_W 560 - #define FRAMEBUFFER_H 384 + // TC: No good as NTSC render code writes to border area: + // . NTSC.cpp: updateVideoScannerHorzEOL(): "NOTE: This writes out-of-bounds for a 560x384 framebuffer" + #define BORDER_W 0 + #define BORDER_H 0 + #define FRAMEBUFFER_W FRAMEBUFFER_BORDERLESS_W + #define FRAMEBUFFER_H FRAMEBUFFER_BORDERLESS_H #else - #define FRAMEBUFFER_W 600 - #define FRAMEBUFFER_H 420 + #define BORDER_W 20 + #define BORDER_H 18 + #define FRAMEBUFFER_W (FRAMEBUFFER_BORDERLESS_W + BORDER_W*2) + #define FRAMEBUFFER_H (FRAMEBUFFER_BORDERLESS_H + BORDER_H*2) #endif // NTSC_END diff --git a/source/Video.cpp b/source/Video.cpp index d24cd128..8412b5c6 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -996,7 +996,7 @@ void VideoDisplayLogo () // Draw Logo at top of screen so when the Apple display is refreshed it will automagically clear it if( g_bIsFullScreen ) { - g_nLogoX = 10; + g_nLogoX = 0; g_nLogoY = 0; } VideoDrawLogoBitmap( hFrameDC, g_nLogoX, g_nLogoY, bm.bmWidth, bm.bmHeight, scale ); @@ -1094,11 +1094,11 @@ void VideoDisplayLogo () //=========================================================================== -void VideoRedrawScreen () +void VideoRedrawScreen (UINT uDelayRefresh /* =0 */) { g_VideoForceFullRedraw = 1; - VideoRefreshScreen( g_uVideoMode ); + VideoRefreshScreen( g_uVideoMode, uDelayRefresh ); } //=========================================================================== @@ -1136,8 +1136,11 @@ static void DebugRefresh(char uDebugFlag) } #endif -void VideoRefreshScreen ( int bVideoModeFlags ) +void VideoRefreshScreen ( int bVideoModeFlags, UINT uDelayRefresh /* =0 */ ) { + static UINT uDelayRefreshCount = 0; + if (uDelayRefresh) uDelayRefreshCount = uDelayRefresh; + #if defined(_DEBUG) && defined(DEBUG_REFRESH_TIMINGS) DebugRefresh(0); #endif @@ -1165,30 +1168,39 @@ void VideoRefreshScreen ( int bVideoModeFlags ) if (hFrameDC) { - // Display the logo for a second so that any full screen screen-caps will have it - static int nLogo = 30; // HACK - if ((nLogo > 0) && nLogo-- ) + if (uDelayRefreshCount) { - int nScale = g_bIsFullScreen ? 1 : GetViewportScale(); - VideoDrawLogoBitmap( hFrameDC, g_nLogoX, g_nLogoY, 560, 384, nScale ); + // Delay the refresh in full-screen mode (to allow screen-capabilities to take effect) - required for Win7 (and others?) + --uDelayRefreshCount; } else + { + int xDst = 0; + int yDst = 0; + + if (g_bIsFullScreen) + { + // Why the need to set the mid-position here, but not for (full-screen) LOGO or DEBUG modes? + xDst = (g_nDDFullScreenW-W)/2 - VIEWPORTX*2; + yDst = (g_nDDFullScreenH-H)/2; + } + StretchBlt( hFrameDC, - 0, 0, - W, // dst - H, // dst + xDst, yDst, // xDst, yDst + W, H, // wDst, hDst g_hDeviceDC, - 0, 0, - FRAMEBUFFER_W, FRAMEBUFFER_H, // src // NOT 560, 384 + BORDER_W, BORDER_H, // xSrc, ySrc + FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // wSrc, hSrc SRCCOPY ); + } } + GdiFlush(); FrameReleaseVideoDC(); - if (g_VideoForceFullRedraw) - --g_VideoForceFullRedraw; + g_VideoForceFullRedraw = 0; // NTSC_END } @@ -1665,8 +1677,8 @@ void Video_MakeScreenShot(FILE *pFile) Video_SetBitmapHeader( pBmp, - g_iScreenshotType ? FRAMEBUFFER_W/2 :FRAMEBUFFER_W, - g_iScreenshotType ? FRAMEBUFFER_H/2 : FRAMEBUFFER_H, + g_iScreenshotType ? FRAMEBUFFER_BORDERLESS_W/2 : FRAMEBUFFER_BORDERLESS_W, + g_iScreenshotType ? FRAMEBUFFER_BORDERLESS_H/2 : FRAMEBUFFER_BORDERLESS_H, 32 ); @@ -1680,14 +1692,13 @@ void Video_MakeScreenShot(FILE *pFile) /**/ sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[0]=0; // Write Header - int nLen; fwrite( pBmp, sizeof( WinBmpHeader_t ), 1, pFile ); uint32_t *pSrc; #if VIDEO_SCREENSHOT_PALETTE // Write Palette Data pSrc = ((uint8_t*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER); - nLen = g_tBmpHeader.nPaletteColors * sizeof(bgra_t); // RGBQUAD + int nLen = g_tBmpHeader.nPaletteColors * sizeof(bgra_t); // RGBQUAD fwrite( pSrc, nLen, 1, pFile ); pSrc += nLen; #endif @@ -1696,7 +1707,8 @@ void Video_MakeScreenShot(FILE *pFile) // No need to use GetDibBits() since we already have http://msdn.microsoft.com/en-us/library/ms532334.aspx // @reference: "Storing an Image" http://msdn.microsoft.com/en-us/library/ms532340(VS.85).aspx pSrc = (uint32_t*) g_pFramebufferbits; - nLen = (g_tBmpHeader.nWidthPixels * g_tBmpHeader.nHeightPixels * g_tBmpHeader.nBitsPerPixel) / 8; + pSrc += BORDER_H * FRAMEBUFFER_W; // Skip top border + pSrc += BORDER_W; // Skip left border if( g_iScreenshotType == SCREENSHOT_280x192 ) { @@ -1708,21 +1720,26 @@ void Video_MakeScreenShot(FILE *pFile) // 50% Half Scan Line clears every odd scanline. // SHIFT+PrintScreen saves only the even rows. // NOTE: Keep in sync with _Video_RedrawScreen() & Video_MakeScreenShot() - for( int y = 0; y < FRAMEBUFFER_H/2; y++ ) + for( int y = 0; y < FRAMEBUFFER_BORDERLESS_H/2; y++ ) { pDst = aScanLine; - for( int x = 0; x < FRAMEBUFFER_W/2; x++ ) + for( int x = 0; x < FRAMEBUFFER_BORDERLESS_W/2; x++ ) { *pDst++ = pSrc[1]; // correction for left edge loss of scaled scanline [Bill Buckel, B#18928] pSrc += 2; // skip odd pixels } - fwrite( aScanLine, FRAMEBUFFER_W/2, 1, pFile ); + fwrite( aScanLine, sizeof(uint32_t), FRAMEBUFFER_BORDERLESS_W/2, pFile ); pSrc += FRAMEBUFFER_W; // scan lines doubled - skip odd ones + pSrc += BORDER_W*2; // Skip right border & next line's left border } } else { - fwrite( pSrc, nLen, 1, pFile ); + for( int y = 0; y < FRAMEBUFFER_BORDERLESS_H; y++ ) + { + fwrite( pSrc, sizeof(uint32_t), FRAMEBUFFER_BORDERLESS_W, pFile ); + pSrc += FRAMEBUFFER_W; + } } #endif // SCREENSHOT_BMP diff --git a/source/Video.h b/source/Video.h index 7bad49f7..a67acf58 100644 --- a/source/Video.h +++ b/source/Video.h @@ -170,8 +170,8 @@ void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, void VideoDisplayLogo (); void VideoInitialize (); void VideoRealizePalette (HDC); -void VideoRedrawScreen (); -void VideoRefreshScreen (int bVideoFlags ); +void VideoRedrawScreen (UINT uDelayRefresh = 0); +void VideoRefreshScreen (int bVideoFlags, UINT uDelayRefresh =0 ); void VideoReinitialize (); void VideoResetState (); WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); From 346f45b3e964095d1d93efb7097b09944fb7286f Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 4 Apr 2016 21:32:40 +0100 Subject: [PATCH 107/121] Fixed: NTSC video mode vars not setup after loading save-state --- source/Frame.cpp | 1 - source/Video.cpp | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 95de5508..98466659 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1719,7 +1719,6 @@ static void ScreenWindowResize(const bool bCtrlKey) nOldViewportScale = g_nViewportScale; FrameResizeWindow(1); // reset to 1x SetFullScreenMode(); - //VideoRedrawScreen(1); // [TC-10/06/2014] Remove this once checked it's not needed by Win8 } } diff --git a/source/Video.cpp b/source/Video.cpp index 8412b5c6..ab4ff8f6 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1338,6 +1338,10 @@ void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode) { g_nAltCharSetOffset = !AltCharSet ? 0 : 256; g_uVideoMode = VideoMode; + +// NTSC_BEGIN + NTSC_SetVideoMode( g_uVideoMode ); +// NTSC_END } // @@ -1369,6 +1373,10 @@ void VideoLoadSnapshot(YamlLoadHelper& yamlLoadHelper) g_uVideoMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_VIDEOMODE); g_dwCyclesThisFrame = yamlLoadHelper.LoadUint(SS_YAML_KEY_CYCLESTHISFRAME); +// NTSC_BEGIN + NTSC_SetVideoMode( g_uVideoMode ); +// NTSC_END + yamlLoadHelper.PopMap(); } From 7e56e9344928605d8adee34556a8fa3b2bcdc2ef Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 4 Apr 2016 22:15:47 +0100 Subject: [PATCH 108/121] Always updateMonoTables() since previous video-mode could have had a non-white RGB value . eg. when cycling backwards from Amber to TV --- source/NTSC.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 85747027..deec0a79 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1509,6 +1509,10 @@ void NTSC_SetVideoStyle() // (int v, int s) switch ( g_eVideoType ) { case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: + r = 0xFF; + g = 0xFF; + b = 0xFF; + updateMonochromeTables( r, g, b ); if (half) { g_pFuncUpdateBnWPixel = updatePixelBnWColorTVSingleScanline; @@ -1522,6 +1526,10 @@ void NTSC_SetVideoStyle() // (int v, int s) case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1: default: + r = 0xFF; + g = 0xFF; + b = 0xFF; + updateMonochromeTables( r, g, b ); if (half) { g_pFuncUpdateBnWPixel = updatePixelBnWMonitorSingleScanline; From 7ccf722200fda3612cf684636e7f95e7f05ca74a Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 4 Apr 2016 22:38:01 +0100 Subject: [PATCH 109/121] Fixed: AltCharSet flag was inverted --- source/Video.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Video.cpp b/source/Video.cpp index ab4ff8f6..b1feaf47 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1322,7 +1322,7 @@ bool VideoGetSWTEXT(void) bool VideoGetSWAltCharSet(void) { - return g_nAltCharSetOffset == 0; + return g_nAltCharSetOffset != 0; } //=========================================================================== From 9adbb1e8e6221f4a8ba404bd073985d9121abb72 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 5 Apr 2016 22:17:29 +0100 Subject: [PATCH 110/121] Added NTSC_Reinitialize() to re-init NTSC state after loading a save-state file --- source/NTSC.cpp | 19 ++++++++++++------- source/NTSC.h | 4 ++-- source/SaveState.cpp | 2 ++ source/Video.cpp | 13 ++++--------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index deec0a79..b3c7d521 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1672,7 +1672,18 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit } //=========================================================================== -void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ) +void NTSC_VideoReinitialize( DWORD cyclesThisFrame ) +{ + _ASSERT(cyclesThisFrame < VIDEO_SCANNER_6502_CYCLES); + if (cyclesThisFrame >= VIDEO_SCANNER_6502_CYCLES) cyclesThisFrame = 0; // error + g_nVideoClockVert = (uint16_t) (cyclesThisFrame / VIDEO_SCANNER_MAX_HORZ); + g_nVideoClockHorz = cyclesThisFrame % VIDEO_SCANNER_MAX_HORZ; + + updateVideoScannerAddress(); // Pre-condition: g_nVideoClockVert +} + +//=========================================================================== +void NTSC_VideoInitAppleType () { int model = g_Apple2Type; @@ -1681,12 +1692,6 @@ void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ) g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; else g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; - - // TC: Move these to a better place (as init'ing these 2 vars is nothing to do with g_Apple2Type) - _ASSERT(cyclesThisFrame < VIDEO_SCANNER_6502_CYCLES); - if (cyclesThisFrame >= VIDEO_SCANNER_6502_CYCLES) cyclesThisFrame = 0; // error - g_nVideoClockVert = (uint16_t) (cyclesThisFrame / VIDEO_SCANNER_MAX_HORZ); - g_nVideoClockHorz = cyclesThisFrame % VIDEO_SCANNER_MAX_HORZ; } //=========================================================================== diff --git a/source/NTSC.h b/source/NTSC.h index a6f3adec..d01bd250 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -13,8 +13,8 @@ extern uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV ); extern uint16_t NTSC_VideoGetScannerAddress( unsigned long cycles6502 ); extern void NTSC_VideoInit( uint8_t *pFramebuffer ); - extern void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ); + extern void NTSC_VideoReinitialize( DWORD cyclesThisFrame ); + extern void NTSC_VideoInitAppleType(); extern void NTSC_VideoInitChroma(); extern bool NTSC_VideoIsVbl(); extern void NTSC_VideoUpdateCycles( long cycles6502 ); - diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 3a771cd8..88254d6a 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -208,6 +208,8 @@ static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) Appl SetLoadedSaveStateFlag(true); MemUpdatePaging(TRUE); + + VideoReinitialize(); // g_CharsetType changed } catch(std::string szMessage) { diff --git a/source/Video.cpp b/source/Video.cpp index b1feaf47..735348a4 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1207,8 +1207,10 @@ void VideoRefreshScreen ( int bVideoModeFlags, UINT uDelayRefresh /* =0 */ ) //=========================================================================== void VideoReinitialize () { - NTSC_VideoInitAppleType(g_dwCyclesThisFrame); + NTSC_VideoReinitialize( g_dwCyclesThisFrame ); + NTSC_VideoInitAppleType(); NTSC_SetVideoStyle(); + NTSC_SetVideoMode( g_uVideoMode ); // Pre-condition: g_nVideoClockHorz (derived from g_dwCyclesThisFrame) } //=========================================================================== @@ -1338,10 +1340,7 @@ void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode) { g_nAltCharSetOffset = !AltCharSet ? 0 : 256; g_uVideoMode = VideoMode; - -// NTSC_BEGIN - NTSC_SetVideoMode( g_uVideoMode ); -// NTSC_END + g_dwCyclesThisFrame = 0; } // @@ -1373,10 +1372,6 @@ void VideoLoadSnapshot(YamlLoadHelper& yamlLoadHelper) g_uVideoMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_VIDEOMODE); g_dwCyclesThisFrame = yamlLoadHelper.LoadUint(SS_YAML_KEY_CYCLESTHISFRAME); -// NTSC_BEGIN - NTSC_SetVideoMode( g_uVideoMode ); -// NTSC_END - yamlLoadHelper.PopMap(); } From 8033455706dbf1b1dc27060cf29eb75ce5bf8a9d Mon Sep 17 00:00:00 2001 From: tomcw Date: Fri, 8 Apr 2016 22:44:07 +0100 Subject: [PATCH 111/121] Use resource CHARSET40.BMP for character set (ToDo: Apple][, Original //e and Pravets) --- source/NTSC_CharSet.cpp | 82 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 4648b82a..89201001 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -23,6 +23,86 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA unsigned char csbits[2][256][8]; +#if 1 + +static const UINT bitmapWidth = 256; +static const UINT bitmapWidthBytes = bitmapWidth/8; +static const UINT bitmapHeight = 768; + +static const UINT charWidth = 16; +static const UINT charWidthBytes = 16/8; +static const UINT charHeight = 16; + +void get_csbits_xy (UINT charset, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap) +{ + _ASSERT(charset < 2); + _ASSERT(ch < 256); + _ASSERT((cx < bitmapWidth/charWidth) && (cy < bitmapHeight/charHeight)); + + pBitmap += cy*charHeight*bitmapWidthBytes + cx*charWidthBytes; + + for (UINT y=0; y<8; y++) + { + BYTE n = 0; + for (int x=0; x<14; x+=2) + { + UINT xp = x/8; + BYTE d = pBitmap[xp]; + UINT b = 7 - x%8; + if (d & (1<>= 1; + } + + csbits[charset][ch][y] = n; + pBitmap += bitmapWidthBytes*2; + } +} + +void make_csbits (void) +{ + HBITMAP hCharBitmap = LoadBitmap(g_hInstance, TEXT("CHARSET40")); + + const UINT bufferSize = bitmapWidthBytes*bitmapHeight; + BYTE* pBuffer = new BYTE [bufferSize]; + GetBitmapBits(hCharBitmap, bufferSize, pBuffer); + + // Enhanced //e: Alt char set off + for (UINT cy=0, ch=0; cy<16; cy++) + { + for (UINT cx=0; cx<16; cx++) + { + get_csbits_xy(0, ch++, cx, cy, pBuffer); + } + } + + // Enhanced //e: Alt char set on (mouse-text) + for (UINT cy=16, ch=0; cy<32; cy++) + { + for (UINT cx=0; cx<16; cx++) + { + get_csbits_xy(1, ch++, cx, cy, pBuffer); + } + } + + #if 0 + // Apple ][, ][+ + // . TODO: Original //e - which had no mouse-text + // . TODO: Pravets + for (UINT cy=32, ch=0; cy<48; cy++) + { + for (UINT cx=0; cx<16; cx++) + { + get_csbits_xy(2, ch++, cx, cy, pBuffer); + } + } + #endif + + delete [] pBuffer; + DeleteObject(hCharBitmap); +} + +#else + static const char *csstrs[] = { " ### "," # "," #### "," ### "," #### "," ##### "," ##### "," #### ", " # # "," # # "," # # "," # # "," # # "," # "," # "," # ", @@ -213,3 +293,5 @@ void make_csbits (void) { csbits[1][i][j] ^= 0xFF; } } + +#endif From 749e1514bde23fd025cc5cf7d60a7767e5f4cc22 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 12 Apr 2016 23:21:05 +0100 Subject: [PATCH 112/121] Use correct resource BMP for each model's character set (Apple ][, original //e and Pravets) Also resized the Pravets BMPs to be either 256 or 512 pixels in height. --- ApplewinExpress9.00.vcproj | 8 +++++ resource/Applewin.rc | 2 +- resource/CHARSET82.bmp | Bin 10302 -> 8254 bytes resource/CHARSET8C.bmp | Bin 24638 -> 16446 bytes resource/CHARSET8M.bmp | Bin 10302 -> 8254 bytes source/Applewin.cpp | 18 ++++++----- source/Common.h | 12 ++++--- source/NTSC.cpp | 21 ++++++++++++- source/NTSC_CharSet.cpp | 62 ++++++++++++++++++------------------- source/NTSC_CharSet.h | 10 +++++- source/Video.cpp | 10 +++--- 11 files changed, 91 insertions(+), 52 deletions(-) diff --git a/ApplewinExpress9.00.vcproj b/ApplewinExpress9.00.vcproj index 5542a063..c46b645f 100644 --- a/ApplewinExpress9.00.vcproj +++ b/ApplewinExpress9.00.vcproj @@ -1078,6 +1078,10 @@ /> + + @@ -1106,6 +1110,10 @@ RelativePath=".\resource\CHARSET8C.bmp" > + + diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 2ba7acc2..5260254e 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -69,7 +69,7 @@ LED_CAPSON_P8_BITMAP BITMAP "LED_CAPS_ON_P8.BMP" LED_LATOFF_BITMAP BITMAP "LED_CAPS_OFF_LAT.BMP" LED_LATON_BITMAP BITMAP "LED_CAPS_ON_LAT.BMP" CHARSET82 BITMAP "CHARSET82.BMP" -CHARSET8M BITMAP "CHARSET8C.BMP" +CHARSET8M BITMAP "CHARSET8M.BMP" CHARSET8C BITMAP "CHARSET8C.BMP" HELP_BUTTON BITMAP "HELP.BMP" DRIVESWAP_BUTTON BITMAP "DRIVESWAP.BMP" diff --git a/resource/CHARSET82.bmp b/resource/CHARSET82.bmp index 0396611b624a2bb352432ca56d0272bfd46df6c2..808fc2e1bcf09d79392cd73d677db9487440a33d 100644 GIT binary patch delta 71 xcmdlNu+PEH$=6PS0SxSbqy~t^2*HeC29T`)#8AKlq(K-2{{R2au-J}60RRpv2h0Ef delta 79 zcmdnzurI*Q$=6PU0SxSbB$&y_z~BJHj6etmKtW+{2xbBbfG`OB|Noz1vV(y9=2(G; I>=9b*a1lm5Q`CrnL!kY0R#yQ48q(H%mn0uFbMqr|9^8W$3f=F zIzp0@{aH9B$Fs>#u49p7vj04J9*Fv|c^}IxCPw4Qk?i$MHXkP6Vz*;5FxV``p~6C< zp2<=iDVysg?lDh}kx-gkCnLvnfM@bN5XC=vpG-Sr{bV;;dB*>n(_}v}GMr+q_Q(=r%O9lcg+FCnrhCPA-t*hhQF-g?0`Aw%k=9 diff --git a/resource/CHARSET8M.bmp b/resource/CHARSET8M.bmp index 53efbb337f3993f9d8bb7bb9638953fe9dbdf615..91dc9dec112be1209d9c7bc2827903ec51f6468e 100644 GIT binary patch delta 71 xcmdlNu+PEH$=6PS0SxSbqy~t^2*HeC29T`)#8AKlq(K-2{{R2au-J}60RRpv2h0Ef delta 79 zcmdnzurI*Q$=6PU0SxSbB$&y_z~BJHj6etmKtW+{2xbBbfG`OB|Noz1vV(y9=2(G; I>= A2TYPE_MAX) || (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE)) dwComputerType = A2TYPE_APPLE2EENHANCED; + // Remap the bad Pravets models (before AppleWin v1.26) + if (dwComputerType == A2TYPE_BAD_PRAVETS82) dwComputerType = A2TYPE_PRAVETS82; + if (dwComputerType == A2TYPE_BAD_PRAVETS8M) dwComputerType = A2TYPE_PRAVETS8M; + apple2Type = (eApple2Type) dwComputerType; } else // Support older AppleWin registry entries diff --git a/source/Common.h b/source/Common.h index 2bc2a071..d69a9647 100644 --- a/source/Common.h +++ b/source/Common.h @@ -166,7 +166,7 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE}; #define IS_APPLE2C (g_Apple2Type & APPLE2C_MASK) #define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK) -// NB. These get persisted to the Registry & save-state file, so don't change the values for these enums! +// NB. These get persisted to the Registry, so don't change the values for these enums! enum eApple2Type { A2TYPE_APPLE2=0, A2TYPE_APPLE2PLUS, @@ -178,10 +178,12 @@ enum eApple2Type { // // Clones start here: A2TYPE_CLONE=APPLECLONE_MASK, - A2TYPE_PRAVETS=APPLECLONE_MASK|APPLE2E_MASK, - A2TYPE_PRAVETS82=A2TYPE_PRAVETS, - A2TYPE_PRAVETS8M, - A2TYPE_PRAVETS8A, + A2TYPE_PRAVETS=APPLECLONE_MASK, + A2TYPE_PRAVETS82=A2TYPE_PRAVETS, // Apple ][ clone + A2TYPE_PRAVETS8M, // Apple ][ clone + A2TYPE_BAD_PRAVETS82=A2TYPE_PRAVETS|APPLE2E_MASK, // Wrongly tagged as Apple //e clone (< AppleWin 1.26) + A2TYPE_BAD_PRAVETS8M, // Wrongly tagged as Apple //e clone (< AppleWin 1.26) + A2TYPE_PRAVETS8A, // Apple //e clone A2TYPE_MAX }; diff --git a/source/NTSC.cpp b/source/NTSC.cpp index b3c7d521..38f78394 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -379,6 +379,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ,{ 255, 255, 255 } // 15 }; + static csbits_t csbits; // charset, optionally followed by alt charset // Prototypes // prototype from CPU.h @@ -433,6 +434,22 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void updateScreenText40 ( long cycles6502 ); static void updateScreenText80 ( long cycles6502 ); +//=========================================================================== +static void set_csbits() +{ + // NB. For models that don't have an alt charset then set /g_nVideoCharSet/ to zero + switch ( GetApple2Type() ) + { + case A2TYPE_APPLE2: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break; + case A2TYPE_APPLE2PLUS: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break; + case A2TYPE_APPLE2E: csbits = &csbits_2e[0]; break; + case A2TYPE_APPLE2EENHANCED:csbits = &csbits_enhanced2e[0]; break; + case A2TYPE_PRAVETS82: csbits = &csbits_pravets82[0]; g_nVideoCharSet = 0; break; // Apple ][ clone + case A2TYPE_PRAVETS8M: csbits = &csbits_pravets8M[0]; g_nVideoCharSet = 0; break; // Apple ][ clone + case A2TYPE_PRAVETS8A: csbits = &csbits_pravets8C[0]; break; // Apple //e clone + default: csbits = &csbits_enhanced2e[0]; break; + } +} //=========================================================================== inline float clampZeroOne( const float & x ) @@ -1685,13 +1702,15 @@ void NTSC_VideoReinitialize( DWORD cyclesThisFrame ) //=========================================================================== void NTSC_VideoInitAppleType () { - int model = g_Apple2Type; + int model = GetApple2Type(); // anything other than low bit set means not II/II+ (TC: include Pravets machines too?) if (model & 0xFFFE) g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; else g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; + + set_csbits(); } //=========================================================================== diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 89201001..93a670f7 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -21,7 +21,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "NTSC_CharSet.h" -unsigned char csbits[2][256][8]; +unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e +unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext) +unsigned char csbits_a2[1][256][8]; // ][ and ][+ +unsigned char csbits_pravets82[1][256][8]; // Pravets 82 +unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M +unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C #if 1 @@ -33,9 +38,8 @@ static const UINT charWidth = 16; static const UINT charWidthBytes = 16/8; static const UINT charHeight = 16; -void get_csbits_xy (UINT charset, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap) +void get_csbits_xy (csbits_t csbits, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap) { - _ASSERT(charset < 2); _ASSERT(ch < 256); _ASSERT((cx < bitmapWidth/charWidth) && (cy < bitmapHeight/charHeight)); @@ -53,56 +57,50 @@ void get_csbits_xy (UINT charset, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap n >>= 1; } - csbits[charset][ch][y] = n; + csbits[0][ch][y] = n; pBitmap += bitmapWidthBytes*2; } } -void make_csbits (void) +void get_csbits (csbits_t csbits, const char* resourceName, const UINT cy0) { - HBITMAP hCharBitmap = LoadBitmap(g_hInstance, TEXT("CHARSET40")); - const UINT bufferSize = bitmapWidthBytes*bitmapHeight; BYTE* pBuffer = new BYTE [bufferSize]; + + HBITMAP hCharBitmap = LoadBitmap(g_hInstance, resourceName); GetBitmapBits(hCharBitmap, bufferSize, pBuffer); - // Enhanced //e: Alt char set off - for (UINT cy=0, ch=0; cy<16; cy++) + for (UINT cy=cy0, ch=0; cy Date: Wed, 20 Apr 2016 22:46:12 +0100 Subject: [PATCH 113/121] -load-state: set CWD to path of .aws.yaml file --- source/Applewin.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 910560f3..6f630871 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1090,6 +1090,14 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (szSnapshotName) { + std::string strPathname(szSnapshotName); + int nIdx = strPathname.find_last_of('\\'); + if (nIdx >= 0 && nIdx+1 < (int)strPathname.length()) + { + std::string strPath = strPathname.substr(0, nIdx+1); + SetCurrentImageDir(strPath.c_str()); + } + // Override value just loaded from Registry by LoadConfiguration() // . NB. Registry value is not updated with this cmd-line value Snapshot_SetFilename(szSnapshotName); From 8a1d39104b3887a3d998749640b3badc3906397a Mon Sep 17 00:00:00 2001 From: Michaelangel007 Date: Thu, 28 Apr 2016 16:08:08 -0700 Subject: [PATCH 114/121] Fix #317 -- some .img using version 0 instead of version 1 --- source/DiskImageHelper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp index c4e8cb26..40bfa214 100644 --- a/source/DiskImageHelper.cpp +++ b/source/DiskImageHelper.cpp @@ -1041,7 +1041,9 @@ eDetectResult C2IMGHelper::DetectHdr(LPBYTE& pImage, DWORD& dwImageSize, DWORD& if (dwImageSize < sizeof(Header2IMG) || pHdr->FormatID != FormatID_2IMG || pHdr->HeaderSize != sizeof(Header2IMG)) return eMismatch; - if (pHdr->Version != 1) + // https://github.com/AppleWin/AppleWin/issues/317 + // Work around some lazy implementations of the spec that set this value to 0 instead of the correct 1. + if (pHdr->Version > 1) return eMismatch; if (dwImageSize < sizeof(Header2IMG)+pHdr->DiskDataLength) From 04c9d09e382dd2132d57050b71efa69294da236e Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 17 May 2016 22:03:45 +0100 Subject: [PATCH 115/121] When FullSpeed: don't do cycle-accurate graphics update . means that disk accesses (eg. loading) is much quicker Correct naming of video modes (in UI and code) Pixel adjust for NTSC B&W and Color video modes to align with other video modes --- source/Applewin.cpp | 4 ++ source/CPU/cpu6502.h | 8 ++-- source/CPU/cpu65C02.h | 8 ++-- source/CPU/cpu65d02.h | 8 ++-- source/Debugger/Debug.cpp | 26 ++++++++++++- source/Debugger/Debugger_Assembler.cpp | 4 ++ source/NTSC.cpp | 8 ++-- source/Video.cpp | 54 +++++++++++++++++++------- source/Video.h | 15 +++---- test/TestCPU6502/TestCPU6502.cpp | 1 + 10 files changed, 100 insertions(+), 36 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 6f630871..a69336f8 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -192,6 +192,7 @@ void ContinueExecution(void) ? g_bScrollLock_FullSpeed : (GetKeyState(VK_SCROLL) < 0); + const bool bWasFullSpeed = g_bFullSpeed; g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) || bScrollLock_FullSpeed || (DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) ); @@ -213,6 +214,9 @@ void ContinueExecution(void) } else { + if (bWasFullSpeed) + VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame); + // Don't call Spkr_Demute() MB_Demute(); SysClk_StartTimerUsec(nExecutionPeriodUsec); diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index b2a25e67..14fe7a24 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -44,7 +44,6 @@ static DWORD Cpu6502 (DWORD uTotalCycles) BYTE iOpcode; // NTSC_BEGIN - ULONG uElapsedCycles; ULONG uPreviousCycles = uExecutedCycles; // NTSC_END @@ -321,8 +320,11 @@ static DWORD Cpu6502 (DWORD uTotalCycles) } // NTSC_BEGIN - uElapsedCycles = uExecutedCycles - uPreviousCycles; - NTSC_VideoUpdateCycles( uElapsedCycles ); + if (!g_bFullSpeed) + { + ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles; + NTSC_VideoUpdateCycles( uElapsedCycles ); + } // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index d9ad28c5..0a1cec26 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -47,7 +47,6 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) BYTE iOpcode; // NTSC_BEGIN - ULONG uElapsedCycles; ULONG uPreviousCycles = uExecutedCycles; // NTSC_END @@ -324,8 +323,11 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) } // NTSC_BEGIN - uElapsedCycles = uExecutedCycles - uPreviousCycles; - NTSC_VideoUpdateCycles( uElapsedCycles ); + if (!g_bFullSpeed) + { + ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles; + NTSC_VideoUpdateCycles( uElapsedCycles ); + } // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index 7c3d34ed..8d72bbcd 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -121,7 +121,6 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) BYTE iOpcode; // NTSC_BEGIN - ULONG uElapsedCycles; ULONG uPreviousCycles = uExecutedCycles; // NTSC_END @@ -409,8 +408,11 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) #undef $ // NTSC_BEGIN - uElapsedCycles = uExecutedCycles - uPreviousCycles; - NTSC_VideoUpdateCycles( uElapsedCycles ); + if (!g_bFullSpeed) + { + ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles; + NTSC_VideoUpdateCycles( uElapsedCycles ); + } // NTSC_END CheckInterruptSources(uExecutedCycles); diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index a985c577..d5892183 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -5095,7 +5095,7 @@ Update_t CmdNTSC (int nArgs) } }; - bool bColorTV = (g_eVideoType == VT_COLOR_TVEMU); + bool bColorTV = (g_eVideoType == VT_COLOR_TV); uint32_t* pChromaTable = NTSC_VideoGetChromaTable( false, bColorTV ); char aStatusText[64] = "Loaded"; @@ -7730,6 +7730,9 @@ bool InternalSingleStep () //=========================================================================== + +#define TRACELINE_WITH_VIDEO_SCANNER_POS 0 + void OutputTraceLine () { DisasmLine_t line; @@ -7747,8 +7750,13 @@ void OutputTraceLine () g_bTraceHeader = false; fprintf( g_hTraceFile, +#if TRACELINE_WITH_VIDEO_SCANNER_POS +// "0000 0000 00 00 00 0000 -------- 0000:90 90 90 NOP" + "Vert Horz A: X: Y: SP: Flags Addr:Opcode Mnemonic\n" +#else // "00 00 00 0000 -------- 0000:90 90 90 NOP" "A: X: Y: SP: Flags Addr:Opcode Mnemonic\n" +#endif ); } @@ -7761,6 +7769,21 @@ void OutputTraceLine () ); } +#if TRACELINE_WITH_VIDEO_SCANNER_POS + fprintf( g_hTraceFile, +// "a=%02x x=%02x y=%02x sp=%03x ps=%s %s\n", + "%04X %04X %02X %02X %02X %04X %s %s\n", + g_nVideoClockVert, + g_nVideoClockHorz, + (unsigned)regs.a, + (unsigned)regs.x, + (unsigned)regs.y, + (unsigned)regs.sp, + (char*) sFlags + , sDisassembly + //, sTarget // TODO: Show target? + ); +#else fprintf( g_hTraceFile, // "a=%02x x=%02x y=%02x sp=%03x ps=%s %s\n", "%02X %02X %02X %04X %s %s\n", @@ -7772,6 +7795,7 @@ void OutputTraceLine () , sDisassembly //, sTarget // TODO: Show target? ); +#endif } } diff --git a/source/Debugger/Debugger_Assembler.cpp b/source/Debugger/Debugger_Assembler.cpp index 4c2730cd..3acc73bd 100644 --- a/source/Debugger/Debugger_Assembler.cpp +++ b/source/Debugger/Debugger_Assembler.cpp @@ -470,6 +470,10 @@ int _6502_GetOpmodeOpbyte ( const int nBaseAddress, int & iOpmode_, int & nOpby if (! g_aOpcodes) { MessageBox( g_hFrameWindow, "Debugger not properly initialized", "ERROR", MB_OK ); + + g_aOpcodes = & g_aOpcodes65C02[ 0 ]; // Enhanced Apple //e + g_aOpmodes[ AM_2 ].m_nBytes = 2; + g_aOpmodes[ AM_3 ].m_nBytes = 3; } #endif diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 38f78394..1bc852b4 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1525,7 +1525,7 @@ void NTSC_SetVideoStyle() // (int v, int s) switch ( g_eVideoType ) { - case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0: + case VT_COLOR_TV: r = 0xFF; g = 0xFF; b = 0xFF; @@ -1541,7 +1541,7 @@ void NTSC_SetVideoStyle() // (int v, int s) } break; - case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1: + case VT_COLOR_MONITOR: default: r = 0xFF; g = 0xFF; @@ -1558,7 +1558,7 @@ void NTSC_SetVideoStyle() // (int v, int s) } break; - case VT_COLOR_TEXT_OPTIMIZED: // VT_MONO_TV: //2: + case VT_MONO_TV: r = 0xFF; g = 0xFF; b = 0xFF; @@ -1591,7 +1591,7 @@ void NTSC_SetVideoStyle() // (int v, int s) b = 0xFF; goto _mono; - case VT_MONO_HALFPIXEL_REAL: + case VT_MONO_CUSTOM: // From WinGDI.h // #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) //#define GetRValue(rgb) (LOBYTE(rgb)) diff --git a/source/Video.cpp b/source/Video.cpp index c8159944..30a1b8cb 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -258,7 +258,7 @@ static LPBYTE vidlastmem = NULL; uint32_t g_uVideoMode = VF_TEXT; // Current Video Mode (this is the last set one as it may change mid-scan line!) - DWORD g_eVideoType = VT_COLOR_TVEMU; + DWORD g_eVideoType = VT_COLOR_TV; DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) @@ -267,27 +267,26 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) // NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc TCHAR g_aVideoChoices[] = - TEXT("Monochrome (Custom Luminance)\0") - TEXT("Color (Standard)\0") - TEXT("Color (Text Optimized)\0") - TEXT("Color (TV emulation)\0") + TEXT("Monochrome (Custom)\0") + TEXT("Color Monitor\0") + TEXT("B&W TV\0") + TEXT("Color TV\0") TEXT("Monochrome (Amber)\0") TEXT("Monochrome (Green)\0") TEXT("Monochrome (White)\0") ; - // AppleWin 1.19.4 VT_COLOR_AUTHENTIC -> VT_COLOR_HALFPIXEL -> VT_COLOR_STANDARD "Color Half-Pixel Authentic // NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc // The window title will be set to this. char *g_apVideoModeDesc[ NUM_VIDEO_MODES ] = { - "Monochrome (Custom)" - , "Standard" - , "Text Optimized" - , "TV" - , "Amber" - , "Green" - , "White" + "Monochrome Monitor (Custom)" + , "Color Monitor" + , "B&W TV" + , "Color TV" + , "Amber Monitor" + , "Green Monitor" + , "White Monitor" }; // Prototypes (Private) _____________________________________________ @@ -1094,6 +1093,18 @@ void VideoDisplayLogo () //=========================================================================== +void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame) +{ + const int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines; + + g_nVideoClockVert = (uint16_t) (dwCyclesThisFrame / kHClocks) % nScanLines; + g_nVideoClockHorz = (uint16_t) (dwCyclesThisFrame % kHClocks); + + VideoRedrawScreen(); // Better (no flicker) than using: NTSC_VideoReinitialize() or VideoReinitialize() +} + +//=========================================================================== + void VideoRedrawScreen (UINT uDelayRefresh /* =0 */) { g_VideoForceFullRedraw = 1; @@ -1185,12 +1196,22 @@ void VideoRefreshScreen ( int bVideoModeFlags, UINT uDelayRefresh /* =0 */ ) yDst = (g_nDDFullScreenH-H)/2; } + int xSrc = BORDER_W; + int ySrc = BORDER_H; + + if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV) + { + // Adjust the src locations for the NTSC video modes + xSrc += 2; + ySrc -= 1; + } + StretchBlt( hFrameDC, xDst, yDst, // xDst, yDst W, H, // wDst, hDst g_hDeviceDC, - BORDER_W, BORDER_H, // xSrc, ySrc + xSrc, ySrc, // xSrc, ySrc FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // wSrc, hSrc SRCCOPY ); } @@ -1397,6 +1418,7 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles) int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines; int nVSyncLine = bVideoScannerNTSC ? kNTSCVSyncLine : kPALVSyncLine; int nScanCycles = nScanLines * kHClocks; + nCycles %= nScanCycles; // calculate horizontal scanning state // @@ -1502,6 +1524,8 @@ bool VideoGetVbl(const DWORD uExecutedCycles) // calculate video parameters according to display standard // int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines; + int nScanCycles = nScanLines * kHClocks; + nCycles %= nScanCycles; // calculate vertical scanning state // @@ -1783,7 +1807,7 @@ void Config_Load_Video() REGLOAD(TEXT(REGVALUE_VIDEO_MONO_COLOR ),&g_nMonochromeRGB); if (g_eVideoType >= NUM_VIDEO_MODES) - g_eVideoType = VT_COLOR_STANDARD; // Old default: VT_COLOR_TVEMU + g_eVideoType = VT_COLOR_MONITOR; } void Config_Save_Video() diff --git a/source/Video.h b/source/Video.h index a67acf58..d27708c4 100644 --- a/source/Video.h +++ b/source/Video.h @@ -6,13 +6,13 @@ // NOTE: Used/Serialized by: g_eVideoType enum VideoType_e { - VT_MONO_HALFPIXEL_REAL // uses custom monochrome - , VT_COLOR_STANDARD - , VT_COLOR_TEXT_OPTIMIZED - , VT_COLOR_TVEMU - , VT_MONO_AMBER // now half pixel - , VT_MONO_GREEN // now half pixel - , VT_MONO_WHITE // now half pixel + VT_MONO_CUSTOM + , VT_COLOR_MONITOR + , VT_MONO_TV + , VT_COLOR_TV + , VT_MONO_AMBER + , VT_MONO_GREEN + , VT_MONO_WHITE , NUM_VIDEO_MODES }; @@ -170,6 +170,7 @@ void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, void VideoDisplayLogo (); void VideoInitialize (); void VideoRealizePalette (HDC); +void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame); void VideoRedrawScreen (UINT uDelayRefresh = 0); void VideoRefreshScreen (int bVideoFlags, UINT uDelayRefresh =0 ); void VideoReinitialize (); diff --git a/test/TestCPU6502/TestCPU6502.cpp b/test/TestCPU6502/TestCPU6502.cpp index df50fe55..a0644924 100644 --- a/test/TestCPU6502/TestCPU6502.cpp +++ b/test/TestCPU6502/TestCPU6502.cpp @@ -4,6 +4,7 @@ #include "../../source/CPU.h" // From Applewin.cpp +bool g_bFullSpeed = false; enum AppMode_e g_nAppMode = MODE_RUNNING; // From Memory.cpp From 42e5d4af47cd3e45eb305d5286f94a6894afc57e Mon Sep 17 00:00:00 2001 From: Michaelangel007 Date: Sat, 21 May 2016 07:58:22 -0700 Subject: [PATCH 116/121] Fixed 2015 Project dependencies to actually use 2015 projects --- AppleWinExpress2015.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AppleWinExpress2015.vcxproj b/AppleWinExpress2015.vcxproj index e9f9a8d2..4f171f93 100644 --- a/AppleWinExpress2015.vcxproj +++ b/AppleWinExpress2015.vcxproj @@ -238,13 +238,13 @@ - + {509739e7-0af3-4c09-a1a9-f0b1bc31b39d} - + {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} - + {0212e0df-06da-4080-bd1d-f3b01599f70f} @@ -459,4 +459,4 @@ - \ No newline at end of file + From 66e468db65604f2ab8e594b4b18af73a1ea26906 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 12 Jul 2016 22:43:31 +0100 Subject: [PATCH 117/121] Merged in Nick's new native resolution full-screen - old 640x480 full-screen deprecated Fixes for: . Logo & Debug window scaled/positioned correctly . Buttons & disk activity (on RHS) drawn in correct position . Crosshairs for mouse (and when using mouse as joystick)drawn in correct position --- source/Debugger/Debugger_Display.cpp | 9 +- source/Frame.cpp | 232 +++++++++++++++++++-------- source/Frame.h | 11 ++ source/Mockingboard.cpp | 8 +- source/Speaker.cpp | 8 +- source/StdAfx.h | 1 + source/Video.cpp | 55 ++++--- source/Video.h | 1 - 8 files changed, 227 insertions(+), 98 deletions(-) diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 5ea53e6b..980ff2c5 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -562,10 +562,15 @@ void StretchBltMemToFrameDC(void) int nViewportCX, nViewportCY; GetViewportCXCY(nViewportCX, nViewportCY); + FULLSCREEN_SCALE_TYPE xdest = g_win_fullscreen_offsetx; + FULLSCREEN_SCALE_TYPE ydest = g_win_fullscreen_offsety; + FULLSCREEN_SCALE_TYPE wdest = nViewportCX; + FULLSCREEN_SCALE_TYPE hdest = nViewportCY; + BOOL bRes = StretchBlt( FrameGetDC(), // HDC hdcDest, - 0, 0, // int nXOriginDest, int nYOriginDest, - nViewportCX, nViewportCY, // int nWidthDest, int nHeightDest, + (int)xdest, (int)(ydest), // int nXOriginDest, int nYOriginDest, + (int)wdest, (int)(hdest), // int nWidthDest, int nHeightDest, GetDebuggerMemDC(), // HDC hdcSrc, 0, 0, // int nXOriginSrc, int nYOriginSrc, FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // int nWidthSrc, int nHeightSrc, diff --git a/source/Frame.cpp b/source/Frame.cpp index 98466659..a67eee8b 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -445,6 +445,8 @@ static void DrawButton (HDC passdc, int number) { } //=========================================================================== + +// NB. x=y=0 means erase only static void DrawCrosshairs (int x, int y) { static int lastx = 0; static int lasty = 0; @@ -454,6 +456,7 @@ static void DrawCrosshairs (int x, int y) { // ERASE THE OLD CROSSHAIRS if (lastx && lasty) +#if 0 if (g_bIsFullScreen) { int loop = 4; while (loop--) { @@ -467,7 +470,25 @@ static void DrawCrosshairs (int x, int y) { FillRect(dc,&rect,(HBRUSH)GetStockObject(BLACK_BRUSH)); } } - else { + else +#else + if (g_bIsFullScreen) + { + int loop = 4; + while (loop--) { + RECT rect = {0,0,5,5}; + switch (loop) { + case 0: OffsetRect(&rect, g_win_fullscreen_offsetx+lastx-2, g_win_fullscreen_offsety+viewporty-5); break; + case 1: OffsetRect(&rect, g_win_fullscreen_offsetx+lastx-2, g_win_fullscreen_offsety+viewporty+g_nViewportCY); break; + case 2: OffsetRect(&rect, g_win_fullscreen_offsetx+viewportx-5, g_win_fullscreen_offsety+lasty-2); break; + case 3: OffsetRect(&rect, g_win_fullscreen_offsetx+viewportx+g_nViewportCX, g_win_fullscreen_offsety+lasty-2); break; + } + FillRect(dc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + } + } + else +#endif + { int loop = 5; while (loop--) { switch (loop) { @@ -492,21 +513,42 @@ static void DrawCrosshairs (int x, int y) { // DRAW THE NEW CROSSHAIRS if (x && y) { - int loop = 4; - while (loop--) { - if ((loop == 1) || (loop == 2)) - SelectObject(dc,GetStockObject(WHITE_PEN)); - else - SelectObject(dc,GetStockObject(BLACK_PEN)); - LINE(x+loop-2,viewporty-5, - x+loop-2,viewporty); - LINE(x+loop-2,viewporty+g_nViewportCY+4, - x+loop-2,viewporty+g_nViewportCY-1); - LINE(viewportx-5, y+loop-2, - viewportx, y+loop-2); - LINE(viewportx+g_nViewportCX+4,y+loop-2, - viewportx+g_nViewportCX-1,y+loop-2); - } + if (g_bIsFullScreen) + { + int loop = 4; + while (loop--) { + if ((loop == 1) || (loop == 2)) + SelectObject(dc,GetStockObject(WHITE_PEN)); + else + SelectObject(dc,GetStockObject(BLACK_PEN)); + LINE(g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty-5, + g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty); + LINE(g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty+g_nViewportCY+4, + g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty+g_nViewportCY-1); + LINE(g_win_fullscreen_offsetx+viewportx-5, g_win_fullscreen_offsety+y+loop-2, + g_win_fullscreen_offsetx+viewportx, g_win_fullscreen_offsety+y+loop-2); + LINE(g_win_fullscreen_offsetx+viewportx+g_nViewportCX+4, g_win_fullscreen_offsety+y+loop-2, + g_win_fullscreen_offsetx+viewportx+g_nViewportCX-1, g_win_fullscreen_offsety+y+loop-2); + } + } + else + { + int loop = 4; + while (loop--) { + if ((loop == 1) || (loop == 2)) + SelectObject(dc,GetStockObject(WHITE_PEN)); + else + SelectObject(dc,GetStockObject(BLACK_PEN)); + LINE(x+loop-2,viewporty-5, + x+loop-2,viewporty); + LINE(x+loop-2,viewporty+g_nViewportCY+4, + x+loop-2,viewporty+g_nViewportCY-1); + LINE(viewportx-5, y+loop-2, + viewportx, y+loop-2); + LINE(viewportx+g_nViewportCX+4,y+loop-2, + viewportx+g_nViewportCX-1,y+loop-2); + } + } } #undef LINE lastx = x; @@ -568,7 +610,8 @@ static void DrawFrameWindow () else if (g_nAppMode == MODE_DEBUG) DebugDisplay(1); else - VideoRedrawScreen(g_bIsFullScreen ? 1 : 0); // On WM_PAINT: delay 1 refresh before rendering full-screen + VideoRedrawScreen(0); // TODO: Presume this is correct with new fullscreen window mode + //VideoRedrawScreen(g_bIsFullScreen ? 1 : 0); // On WM_PAINT: delay 1 refresh before rendering full-screen if (g_bPaintingWindow) EndPaint(g_hFrameWindow,&ps); @@ -2044,6 +2087,14 @@ void SetFullScreen32Bit(bool b32Bit) g_bFullScreen32Bit = b32Bit; } +// TODO: Put this stuff in a header / somewhere sensible +RECT g_main_window_saved_rect; +int g_main_window_saved_style; +int g_main_window_saved_exstyle; +FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale = 1; +int g_win_fullscreen_offsetx = 0; +int g_win_fullscreen_offsety = 0; + void SetFullScreenMode () { #ifdef NO_DIRECT_X @@ -2052,38 +2103,77 @@ void SetFullScreenMode () #else // NO_DIRECT_X - g_bIsFullScreen = true; + MONITORINFO monitor_info; + FULLSCREEN_SCALE_TYPE width, height, scalex, scaley; + int top, left, A2_WINDOW_WIDTH, A2_WINDOW_HEIGHT; + + GetWidthHeight(A2_WINDOW_WIDTH, A2_WINDOW_HEIGHT); + buttonover = -1; +#if 0 + // FS: 640x480 buttonx = FSBUTTONX; buttony = FSBUTTONY; viewportx = FSVIEWPORTX; viewporty = FSVIEWPORTY; - GetWindowRect(g_hFrameWindow,&framerect); - SetWindowLong(g_hFrameWindow,GWL_STYLE,WS_POPUP | WS_SYSMENU | WS_VISIBLE); - - DDSURFACEDESC ddsd; - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; - ddsd.dwBackBufferCount = 1; - - DDSCAPS ddscaps; - ddscaps.dwCaps = DDSCAPS_BACKBUFFER; - - if ( 0 - || DD_OK != DirectDrawCreate(NULL,&g_pDD,NULL) - || DD_OK != g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) - || DD_OK != g_pDD->SetDisplayMode(g_nDDFullScreenW,g_nDDFullScreenH,32) - || DD_OK != g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) -#if DIRECTX_PAGE_FLIP - || DD_OK != g_pDDPrimarySurface->GetAttachedSurface( &ddscaps, &g_pDDBackSurface) #endif - ) - { - g_pDDPrimarySurface = NULL; - SetNormalMode(); - return; - } + + g_main_window_saved_style = GetWindowLong(g_hFrameWindow, GWL_STYLE); + g_main_window_saved_exstyle = GetWindowLong(g_hFrameWindow, GWL_EXSTYLE); + GetWindowRect(g_hFrameWindow, &g_main_window_saved_rect); + SetWindowLong(g_hFrameWindow, GWL_STYLE, g_main_window_saved_style & ~(WS_CAPTION | WS_THICKFRAME)); + SetWindowLong(g_hFrameWindow, GWL_EXSTYLE, g_main_window_saved_exstyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfo(MonitorFromWindow(g_hFrameWindow, MONITOR_DEFAULTTONEAREST), &monitor_info); + left = monitor_info.rcMonitor.left; + top = monitor_info.rcMonitor.top; + width = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.right - monitor_info.rcMonitor.left); + height = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top); + scalex = width / A2_WINDOW_WIDTH; + scaley = height / A2_WINDOW_HEIGHT; + g_win_fullscreen_scale = (scalex <= scaley) ? scalex : scaley; + g_win_fullscreen_offsetx = ((int)width - (int)(g_win_fullscreen_scale * A2_WINDOW_WIDTH)) / 2; + g_win_fullscreen_offsety = ((int)height - (int)(g_win_fullscreen_scale * A2_WINDOW_HEIGHT)) / 2; + SetWindowPos(g_hFrameWindow, NULL, left, top, (int)width, (int)height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + g_bIsFullScreen = true; + +#if 1 + // FS: desktop + SetViewportScale(g_win_fullscreen_scale); + + buttonx = g_win_fullscreen_offsetx + g_nViewportCX + VIEWPORTX*2; + buttony = g_win_fullscreen_offsety; + viewportx = VIEWPORTX; + viewporty = VIEWPORTY; +#endif + + // GetWindowRect(g_hFrameWindow,&framerect); +// SetWindowLong(g_hFrameWindow,GWL_STYLE,WS_POPUP | WS_SYSMENU | WS_VISIBLE); +// +// DDSURFACEDESC ddsd; +// ddsd.dwSize = sizeof(ddsd); +// ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; +// ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; +// ddsd.dwBackBufferCount = 1; +// +// DDSCAPS ddscaps; +// ddscaps.dwCaps = DDSCAPS_BACKBUFFER; +// +// if ( 0 +// || DD_OK != DirectDrawCreate(NULL,&g_pDD,NULL) +// || DD_OK != g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) +// || DD_OK != g_pDD->SetDisplayMode(g_nDDFullScreenW,g_nDDFullScreenH,32) +// || DD_OK != g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) +//#if DIRECTX_PAGE_FLIP +// || DD_OK != g_pDDPrimarySurface->GetAttachedSurface( &ddscaps, &g_pDDBackSurface) +//#endif +// ) +// { +// g_pDDPrimarySurface = NULL; +// SetNormalMode(); +// return; +// } InvalidateRect(g_hFrameWindow,NULL,1); @@ -2093,30 +2183,44 @@ void SetFullScreenMode () //=========================================================================== void SetNormalMode () { - g_bIsFullScreen = false; +// g_bIsFullScreen = false; buttonover = -1; buttonx = BUTTONX; buttony = BUTTONY; viewportx = VIEWPORTX; viewporty = VIEWPORTY; - g_pDD->RestoreDisplayMode(); - g_pDD->SetCooperativeLevel(NULL,DDSCL_NORMAL); - SetWindowLong(g_hFrameWindow,GWL_STYLE, - WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | - WS_VISIBLE); - SetWindowPos(g_hFrameWindow,0,framerect.left, - framerect.top, - framerect.right - framerect.left, - framerect.bottom - framerect.top, - SWP_NOZORDER | SWP_FRAMECHANGED); - if (g_pDDPrimarySurface) - { - g_pDDPrimarySurface->Release(); - g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0; - } - g_pDD->Release(); - g_pDD = (LPDIRECTDRAW)0; + g_win_fullscreen_offsetx = 0; + g_win_fullscreen_offsety = 0; + g_win_fullscreen_scale = 1; + SetWindowLong(g_hFrameWindow, GWL_STYLE, g_main_window_saved_style); + SetWindowLong(g_hFrameWindow, GWL_EXSTYLE, g_main_window_saved_exstyle); + SetWindowPos(g_hFrameWindow, NULL, + g_main_window_saved_rect.left, + g_main_window_saved_rect.top, + g_main_window_saved_rect.right - g_main_window_saved_rect.left, + g_main_window_saved_rect.bottom - g_main_window_saved_rect.top, + SWP_SHOWWINDOW); + g_bIsFullScreen = false; + + //g_pDD->RestoreDisplayMode(); + //g_pDD->SetCooperativeLevel(NULL,DDSCL_NORMAL); + //SetWindowLong(g_hFrameWindow,GWL_STYLE, + // WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + // WS_VISIBLE); + //SetWindowPos(g_hFrameWindow,0,framerect.left, + // framerect.top, + // framerect.right - framerect.left, + // framerect.bottom - framerect.top, + // SWP_NOZORDER | SWP_FRAMECHANGED); + //if (g_pDDPrimarySurface) + //{ + // g_pDDPrimarySurface->Release(); + // g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0; + //} + + //g_pDD->Release(); + //g_pDD = (LPDIRECTDRAW)0; } //=========================================================================== @@ -2358,7 +2462,8 @@ HDC FrameGetVideoDC (LPBYTE *pAddr_, LONG *pPitch_) // ASSERT( pAddr_ ); // ASSERT( pPitch_ ); - if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow) + if (false) // TODO: ... + //if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow) { // Reference: http://archive.gamedev.net/archive/reference/articles/article608.html // NTSC TODO: Are these coordinates correct?? Coordinates don't seem to matter on Win7 fullscreen!? @@ -2434,7 +2539,8 @@ void FrameReleaseDC () { //=========================================================================== void FrameReleaseVideoDC () { - if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow) + if (false) // TODO: ... + //if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow) { // THIS IS CORRECT ACCORDING TO THE DIRECTDRAW DOCS RECT rect = { diff --git a/source/Frame.h b/source/Frame.h index a0005704..171ccd26 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -51,6 +51,17 @@ extern bool g_bScrollLock_FullSpeed; extern int g_nCharsetType; + +#if 0 // enable non-integral full-screen scaling +#define FULLSCREEN_SCALE_TYPE float +#else +#define FULLSCREEN_SCALE_TYPE int +#endif +extern FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale; +extern int g_win_fullscreen_offsetx; +extern int g_win_fullscreen_offsety; + + // Prototypes void CtrlReset(); diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 0143f8e9..8126bac1 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -828,8 +828,8 @@ static void MB_Update() if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor)) { double fTicksSecs = (double)GetTickCount() / 1000.0; - sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); - OutputDebugString(szDbg); + //sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); + //OutputDebugString(szDbg); if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; @@ -841,8 +841,8 @@ static void MB_Update() if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor)) { double fTicksSecs = (double)GetTickCount() / 1000.0; - sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); - OutputDebugString(szDbg); + //sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); + //OutputDebugString(szDbg); if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; diff --git a/source/Speaker.cpp b/source/Speaker.cpp index fcf1dd9f..f7b23d79 100644 --- a/source/Speaker.cpp +++ b/source/Speaker.cpp @@ -870,8 +870,8 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples) if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor)) { double fTicksSecs = (double)GetTickCount() / 1000.0; - sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); - OutputDebugString(szDbg); + //sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); + //OutputDebugString(szDbg); if (g_fh) fprintf(g_fh, szDbg); dwByteOffset = dwCurrentWriteCursor; @@ -885,8 +885,8 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples) if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor)) { double fTicksSecs = (double)GetTickCount() / 1000.0; - sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); - OutputDebugString(szDbg); + //sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); + //OutputDebugString(szDbg); if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; diff --git a/source/StdAfx.h b/source/StdAfx.h index 6befb99a..e4c4f02a 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -4,6 +4,7 @@ // . See: http://support.embarcadero.com/article/35754 // . "GetOpenFileName() fails under Windows 95/98/NT/ME due to incorrect OPENFILENAME structure size" #define _WIN32_WINNT 0x0400 +#define WINVER 0x500 // Mouse Wheel is not supported on Win95. // If we didn't care about supporting Win95 (compile/run-time errors) diff --git a/source/Video.cpp b/source/Video.cpp index 30a1b8cb..3d2ac655 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -951,7 +951,7 @@ void VideoDestroy () { //=========================================================================== -void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale) +static void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale) { HDC hSrcDC = CreateCompatibleDC( hDstDC ); SelectObject( hSrcDC, g_hLogoBitmap ); @@ -968,15 +968,11 @@ void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int DeleteObject( hSrcDC ); } -int g_nLogoWidth = FRAMEBUFFER_W; -int g_nLogoX = 0; -int g_nLogoY = 0; - //=========================================================================== void VideoDisplayLogo () { - int xoff = 0, yoff = 0; - const int scale = GetViewportScale(); + int nLogoX = 0, nLogoY = 0; + int scale = GetViewportScale(); HDC hFrameDC = FrameGetDC(); @@ -988,17 +984,21 @@ void VideoDisplayLogo () BITMAP bm; if (GetObject(g_hLogoBitmap, sizeof(bm), &bm)) { - g_nLogoWidth = bm.bmWidth; - g_nLogoX = (g_nViewportCX - scale*g_nLogoWidth)/2; - g_nLogoY = (g_nViewportCY - scale*bm.bmHeight )/2; + nLogoX = (g_nViewportCX - scale*bm.bmWidth )/2; + nLogoY = (g_nViewportCY - scale*bm.bmHeight)/2; - // Draw Logo at top of screen so when the Apple display is refreshed it will automagically clear it if( g_bIsFullScreen ) { - g_nLogoX = 0; - g_nLogoY = 0; +#if 0 + // Draw Logo at top of screen so when the Apple display is refreshed it will automagically clear it + nLogoX = 0; + nLogoY = 0; +#else + nLogoX += g_win_fullscreen_offsetx; + nLogoY += g_win_fullscreen_offsety; +#endif } - VideoDrawLogoBitmap( hFrameDC, g_nLogoX, g_nLogoY, bm.bmWidth, bm.bmHeight, scale ); + VideoDrawLogoBitmap( hFrameDC, nLogoX, nLogoY, bm.bmWidth, bm.bmHeight, scale ); } } @@ -1014,6 +1014,7 @@ void VideoDisplayLogo () char szVersion[ 64 ] = ""; sprintf( szVersion, "Version %s", VERSIONSTRING ); + int xoff = g_win_fullscreen_offsetx, yoff = g_win_fullscreen_offsety; #define DRAWVERSION(x,y,c) \ SetTextColor(hFrameDC,c); \ @@ -1067,15 +1068,15 @@ void VideoDisplayLogo () // sprintf( szVersion, "NTSC Alpha v17 BMP Palette" ); sprintf( szVersion, "NTSC Alpha v18" ); - xoff = -g_nViewportCX + g_nViewportCX/6; - yoff = -g_nViewportCY/16; + xoff = -g_nViewportCX + g_nViewportCX/6 + g_win_fullscreen_offsetx; + yoff = -g_nViewportCY/16 + g_win_fullscreen_offsety; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); sprintf( szVersion, "Blurry 80-col Text" ); - xoff = -g_nViewportCX + g_nViewportCX/6; - yoff = +g_nViewportCY/16; + xoff = -g_nViewportCX + g_nViewportCX/6 + g_win_fullscreen_offsetx; + yoff = +g_nViewportCY/16 + g_win_fullscreen_offsety; DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); @@ -1206,14 +1207,20 @@ void VideoRefreshScreen ( int bVideoModeFlags, UINT uDelayRefresh /* =0 */ ) ySrc -= 1; } + FULLSCREEN_SCALE_TYPE xdest = g_win_fullscreen_offsetx; + FULLSCREEN_SCALE_TYPE ydest = g_win_fullscreen_offsety; + FULLSCREEN_SCALE_TYPE wdest = g_nViewportCX /** g_win_fullscreen_scale*/; + FULLSCREEN_SCALE_TYPE hdest = g_nViewportCY /** g_win_fullscreen_scale*/; + + SetStretchBltMode(hFrameDC, COLORONCOLOR); StretchBlt( - hFrameDC, - xDst, yDst, // xDst, yDst - W, H, // wDst, hDst + hFrameDC, + (int)xdest, (int)ydest, + (int)wdest, (int)hdest, g_hDeviceDC, - xSrc, ySrc, // xSrc, ySrc - FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // wSrc, hSrc - SRCCOPY ); + xSrc, ySrc, + FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, + SRCCOPY); } } diff --git a/source/Video.h b/source/Video.h index d27708c4..53df0366 100644 --- a/source/Video.h +++ b/source/Video.h @@ -166,7 +166,6 @@ BOOL VideoApparentlyDirty (); void VideoBenchmark (); void VideoChooseMonochromeColor (); // FIXME: Should be moved to PageConfig and call VideoSetMonochromeColor() void VideoDestroy (); -void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale); void VideoDisplayLogo (); void VideoInitialize (); void VideoRealizePalette (HDC); From 02b0d7419a96051a913dac806f5d2e7412d9f85e Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 23 Jul 2016 22:53:29 +0100 Subject: [PATCH 118/121] Fixed screen update when running at full-speed . Specifically IBIZA.DSK demo which streams data from the disk throughout (ie. so runs at full-speed all the time) . Update the screen every frame, but only if video memory has changed (check AZTEC.DSK loading time) . NB. When running at full-speed, then 6502 emulation doesn't do cycle-accurate video updates Fixed crash that could occur when switch video mode (F9) when running at full-speed . Occured when g_nVideoClockVert was >= 192 --- source/Applewin.cpp | 16 +++++++++++++ source/Applewin.h | 1 + source/Frame.cpp | 7 +++--- source/NTSC.cpp | 8 +++---- source/Video.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++ source/Video.h | 1 + 6 files changed, 82 insertions(+), 7 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index a69336f8..6e40438f 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -79,6 +79,7 @@ TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save BOOL restart = 0; +bool g_bRestartFullScreen = false; DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar double g_fCurrentCLK6502 = CLK_6502; // Affected by Config dialog's speed slider bar @@ -215,7 +216,10 @@ void ContinueExecution(void) else { if (bWasFullSpeed) + { + VideoRedrawScreenDuringFullSpeed(0, true); // Invalidate the copies of video memory VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame); + } // Don't call Spkr_Demute() MB_Demute(); @@ -247,6 +251,12 @@ void ContinueExecution(void) { g_dwCyclesThisFrame -= dwClksPerFrame; + if (g_bFullSpeed) + { + // For IBIZA.DSK + VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame); + } + VideoRefreshScreen(0); // Just copy the output of our Apple framebuffer to the system Back Buffer MB_EndOfVideoFrame(); } @@ -1146,6 +1156,12 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) EnterMessageLoop(); LogFileOutput("Main: LeaveMessageLoop()\n"); + if (restart) + { + bSetFullScreen = g_bRestartFullScreen; + g_bRestartFullScreen = false; + } + MB_Reset(); LogFileOutput("Main: MB_Reset()\n"); diff --git a/source/Applewin.h b/source/Applewin.h index b57efcde..43baf895 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -31,6 +31,7 @@ extern TCHAR g_sProgramDir[MAX_PATH]; extern TCHAR g_sCurrentDir[MAX_PATH]; extern BOOL restart; +extern bool g_bRestartFullScreen; extern DWORD g_dwSpeed; extern double g_fCurrentCLK6502; diff --git a/source/Frame.cpp b/source/Frame.cpp index a67eee8b..3c5d83b0 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -978,6 +978,8 @@ LRESULT CALLBACK FrameWndProc ( case WM_CLOSE: LogFileOutput("WM_CLOSE\n"); + if (g_bIsFullScreen && restart) + g_bRestartFullScreen = true; if (g_bIsFullScreen) SetNormalMode(); if (!IsIconic(window)) @@ -1224,10 +1226,9 @@ LRESULT CALLBACK FrameWndProc ( DrawStatusArea( (HDC)0, DRAW_TITLE ); VideoReinitialize(); - if ((g_nAppMode != MODE_LOGO) || ((g_nAppMode == MODE_DEBUG) && (g_bDebuggerViewingAppleOutput))) + if (g_nAppMode != MODE_LOGO) { - //VideoRedrawScreen(); - VideoRefreshScreen( g_bDebuggerViewingAppleOutput ); + VideoRefreshScreen( g_nAppMode == MODE_DEBUG ? g_bDebuggerViewingAppleOutput : 0); } Config_Save_Video(); diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 1bc852b4..6bcaeb97 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -121,10 +121,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text #define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines - uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ]; + static uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ]; - bgra_t *g_pVideoAddress = 0; - bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 + static bgra_t *g_pVideoAddress = 0; + static bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384 static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; @@ -770,7 +770,7 @@ inline void updateVideoScannerHorzEOL() //=========================================================================== inline void updateVideoScannerAddress() { - g_pVideoAddress = g_pScanLines[2*g_nVideoClockVert]; + g_pVideoAddress = g_nVideoClockVert Date: Mon, 25 Jul 2016 21:19:00 +0100 Subject: [PATCH 119/121] Calculate full-screen scale using borderless dimensions & allow more than 2x scale --- source/Applewin.cpp | 1 - source/Frame.cpp | 13 +++++++------ source/Frame.h | 2 +- source/Video.cpp | 11 +++++++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 6e40438f..c95bb52f 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -253,7 +253,6 @@ void ContinueExecution(void) if (g_bFullSpeed) { - // For IBIZA.DSK VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame); } diff --git a/source/Frame.cpp b/source/Frame.cpp index 3c5d83b0..6ea59283 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -68,7 +68,7 @@ static const int kDEFAULT_VIEWPORT_SCALE = 2; int g_nViewportCX = FRAMEBUFFER_BORDERLESS_W * kDEFAULT_VIEWPORT_SCALE; int g_nViewportCY = FRAMEBUFFER_BORDERLESS_H * kDEFAULT_VIEWPORT_SCALE; static int g_nViewportScale = kDEFAULT_VIEWPORT_SCALE; // saved REGSAVE -static int g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE; +static int g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE; // Max scale in Windowed mode with borders, buttons etc (full-screen may be +1) #define BUTTONX (g_nViewportCX + VIEWPORTX*2) #define BUTTONY 0 @@ -2106,9 +2106,10 @@ void SetFullScreenMode () MONITORINFO monitor_info; FULLSCREEN_SCALE_TYPE width, height, scalex, scaley; - int top, left, A2_WINDOW_WIDTH, A2_WINDOW_HEIGHT; + int top, left; - GetWidthHeight(A2_WINDOW_WIDTH, A2_WINDOW_HEIGHT); + const int A2_WINDOW_WIDTH = FRAMEBUFFER_BORDERLESS_W; + const int A2_WINDOW_HEIGHT = FRAMEBUFFER_BORDERLESS_H; buttonover = -1; #if 0 @@ -2141,7 +2142,7 @@ void SetFullScreenMode () #if 1 // FS: desktop - SetViewportScale(g_win_fullscreen_scale); + SetViewportScale(g_win_fullscreen_scale, true); buttonx = g_win_fullscreen_offsetx + g_nViewportCX + VIEWPORTX*2; buttony = g_win_fullscreen_offsety; @@ -2261,9 +2262,9 @@ int GetViewportScale(void) return g_nViewportScale; } -int SetViewportScale(int nNewScale) +int SetViewportScale(int nNewScale, bool bForce /*=false*/) { - if (nNewScale > g_nMaxViewportScale) + if (!bForce && nNewScale > g_nMaxViewportScale) nNewScale = g_nMaxViewportScale; g_nViewportScale = nNewScale; diff --git a/source/Frame.h b/source/Frame.h index 171ccd26..7ded8b69 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -74,7 +74,7 @@ extern int g_win_fullscreen_offsety; void FrameReleaseVideoDC (); void FrameSetCursorPosByMousePos(); int GetViewportScale(void); - int SetViewportScale(int nNewScale); + int SetViewportScale(int nNewScale, bool bForce = false); void GetViewportCXCY(int& nViewportCX, int& nViewportCY); bool GetFullScreen32Bit(void); void SetFullScreen32Bit(bool b32Bit); diff --git a/source/Video.cpp b/source/Video.cpp index ff200ccc..b2f256dd 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1103,10 +1103,6 @@ void VideoDisplayLogo () void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInvalidate /*=false*/) { static bool bValid = false; - static BYTE text_main[1024*2] = {0}; // page1 & 2 - static BYTE text_aux[1024*2] = {0}; // page1 & 2 - static BYTE hgr_main[8192*2] = {0}; // page1 & 2 - static BYTE hgr_aux[8192*2] = {0}; // page1 & 2 if (bInvalidate) { @@ -1114,6 +1110,13 @@ void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInvalidate return; } + // + + static BYTE text_main[1024*2] = {0}; // page1 & 2 + static BYTE text_aux[1024*2] = {0}; // page1 & 2 + static BYTE hgr_main[8192*2] = {0}; // page1 & 2 + static BYTE hgr_aux[8192*2] = {0}; // page1 & 2 + bool bRedraw = true; // Always redraw for bValid==false (ie. just entered full-speed mode) if (bValid) From 94b8e76e3b64e39120b612a12a985957a633b662 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 26 Jul 2016 19:14:06 +0100 Subject: [PATCH 120/121] Small tidy-up for NTSC_CharSet.cpp, and fix-up the VS2008/2013/2015 projects --- AppleWinExpress2013.vcxproj | 2 + AppleWinExpress2013.vcxproj.filters | 6 + AppleWinExpress2015.vcxproj | 4 +- AppleWinExpress2015.vcxproj.filters | 6 + ApplewinExpress9.00.vcproj | 4 + source/NTSC.cpp | 4 +- source/NTSC_CharSet.cpp | 207 +--------------------------- source/NTSC_CharSet.h | 27 +--- 8 files changed, 32 insertions(+), 228 deletions(-) diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj index 6d0c6dba..8c96fb9c 100644 --- a/AppleWinExpress2013.vcxproj +++ b/AppleWinExpress2013.vcxproj @@ -75,6 +75,7 @@ + @@ -130,6 +131,7 @@ + diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters index c9b778eb..d35fad61 100644 --- a/AppleWinExpress2013.vcxproj.filters +++ b/AppleWinExpress2013.vcxproj.filters @@ -181,6 +181,9 @@ Source Files\Emulator + + Source Files\Video + @@ -444,6 +447,9 @@ Source Files\_Headers + + Source Files\Video + diff --git a/AppleWinExpress2015.vcxproj b/AppleWinExpress2015.vcxproj index 4f171f93..b47e1470 100644 --- a/AppleWinExpress2015.vcxproj +++ b/AppleWinExpress2015.vcxproj @@ -75,6 +75,7 @@ + @@ -130,6 +131,7 @@ + @@ -459,4 +461,4 @@ - + \ No newline at end of file diff --git a/AppleWinExpress2015.vcxproj.filters b/AppleWinExpress2015.vcxproj.filters index c9b778eb..d35fad61 100644 --- a/AppleWinExpress2015.vcxproj.filters +++ b/AppleWinExpress2015.vcxproj.filters @@ -181,6 +181,9 @@ Source Files\Emulator + + Source Files\Video + @@ -444,6 +447,9 @@ Source Files\_Headers + + Source Files\Video + diff --git a/ApplewinExpress9.00.vcproj b/ApplewinExpress9.00.vcproj index c46b645f..aa4af152 100644 --- a/ApplewinExpress9.00.vcproj +++ b/ApplewinExpress9.00.vcproj @@ -878,6 +878,10 @@ RelativePath=".\source\NTSC.h" > + + diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 6bcaeb97..09c19f9d 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -2,7 +2,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 2010-2011, William S Simms -Copyright (C) 2014-2015 Michael Pohoreski +Copyright (C) 2014-2016, Michael Pohoreski, Tom Charlesworth AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Video.h" // g_pFramebufferbits #include "NTSC.h" - #include "NTSC_CharSet.cpp" + #include "NTSC_CharSet.h" #define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white has chroma, 1 = pure white without chroma tinting #define NTSC_REMOVE_BLACK_GHOSTING 1 // 1 = remove black smear/smudges carrying over diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 93a670f7..ce940e51 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -2,6 +2,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 2010-2011, William S Simms +Copyright (C) 2016, Tom Charlesworth AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +20,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "StdAfx.h" +#include "AppleWin.h" + #include "NTSC_CharSet.h" unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e @@ -28,7 +31,7 @@ unsigned char csbits_pravets82[1][256][8]; // Pravets 82 unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C -#if 1 +// static const UINT bitmapWidth = 256; static const UINT bitmapWidthBytes = bitmapWidth/8; @@ -38,7 +41,7 @@ static const UINT charWidth = 16; static const UINT charWidthBytes = 16/8; static const UINT charHeight = 16; -void get_csbits_xy (csbits_t csbits, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap) +static void get_csbits_xy(csbits_t csbits, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap) { _ASSERT(ch < 256); _ASSERT((cx < bitmapWidth/charWidth) && (cy < bitmapHeight/charHeight)); @@ -62,7 +65,7 @@ void get_csbits_xy (csbits_t csbits, UINT ch, UINT cx, UINT cy, const BYTE* pBit } } -void get_csbits (csbits_t csbits, const char* resourceName, const UINT cy0) +static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0) { const UINT bufferSize = bitmapWidthBytes*bitmapHeight; BYTE* pBuffer = new BYTE [bufferSize]; @@ -83,7 +86,7 @@ void get_csbits (csbits_t csbits, const char* resourceName, const UINT cy0) delete [] pBuffer; } -void make_csbits (void) +void make_csbits(void) { get_csbits(&csbits_enhanced2e[0], TEXT("CHARSET40"), 0); // Enhanced //e: Alt char set off get_csbits(&csbits_enhanced2e[1], TEXT("CHARSET40"), 16); // Enhanced //e: Alt char set on (mousetext) @@ -97,199 +100,3 @@ void make_csbits (void) memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e)); memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8); } - -#else - -// NB. '(', ')' are 1 bit out of alignment -static const char *csstrs[] = { - " ### "," # "," #### "," ### "," #### "," ##### "," ##### "," #### ", - " # # "," # # "," # # "," # # "," # # "," # "," # "," # ", - " # # # "," # # "," # # "," # "," # # "," # "," # "," # ", - " # ### "," # # "," #### "," # "," # # "," #### "," #### "," # ", - " # ## "," ##### "," # # "," # "," # # "," # "," # "," # ## ", - " # "," # # "," # # "," # # "," # # "," # "," # "," # # ", - " #### "," # # "," #### "," ### "," #### "," ##### "," # "," #### ", - " "," "," "," "," "," "," "," ", - " # # "," ### "," # "," # # "," # "," # # "," # # "," ### ", - " # # "," # "," # "," # # "," # "," ## ## "," # # "," # # ", - " # # "," # "," # "," # # "," # "," # # # "," ## # "," # # ", - " ##### "," # "," # "," ## "," # "," # # # "," # # # "," # # ", - " # # "," # "," # "," # # "," # "," # # "," # ## "," # # ", - " # # "," # "," # # "," # # "," # "," # # "," # # "," # # ", - " # # "," ### "," ### "," # # "," ##### "," # # "," # # "," ### ", - " "," "," "," "," "," "," "," ", - " #### "," ### "," #### "," ### "," ##### "," # # "," # # "," # # ", - " # # "," # # "," # # "," # # "," # "," # # "," # # "," # # ", - " # # "," # # "," # # "," # "," # "," # # "," # # "," # # ", - " #### "," # # "," #### "," ### "," # "," # # "," # # "," # # # ", - " # "," # # # "," # # "," # "," # "," # # "," # # "," # # # ", - " # "," # # "," # # "," # # "," # "," # # "," # # "," ## ## ", - " # "," ## # "," # # "," ### "," # "," ### "," # "," # # ", - " "," "," "," "," "," "," "," ", - " # # "," # # "," ##### "," ##### "," "," ##### "," "," ", - " # # "," # # "," # "," ## "," # "," ## "," "," ", - " # # "," # # "," # "," ## "," # "," ## "," # "," ", - " # "," # "," # "," ## "," # "," ## "," # # "," ", - " # # "," # "," # "," ## "," # "," ## "," # # "," ", - " # # "," # "," # "," ## "," # "," ## "," "," ", - " # # "," # "," ##### "," ##### "," "," ##### "," "," ", - " "," "," "," "," "," "," "," #######", - " "," # "," # # "," # # "," # "," ## "," # "," # ", - " "," # "," # # "," # # "," #### "," ## # "," # # "," # ", - " "," # "," # # "," ##### "," # # "," # "," # # "," # ", - " "," # "," "," # # "," ### "," # "," # "," ", - " "," # "," "," ##### "," # # "," # "," # # # "," ", - " "," "," "," # # "," #### "," # ## "," # # "," ", - " "," # "," "," # # "," # "," ## "," ## # "," ", - " "," "," "," "," "," "," "," ", - " # "," # "," # "," "," "," "," "," ", - " # "," # "," # # # "," # "," "," "," "," # ", - " # "," # "," ### "," # "," "," "," "," # ", - " # "," # "," # "," ##### "," "," ##### "," "," # ", - " # "," # "," ### "," # "," # "," "," "," # ", - " # "," # "," # # # "," # "," # "," "," "," # ", - " # "," # "," # "," "," # "," "," # "," ", - " "," "," "," "," "," "," "," ", - " ### "," # "," ### "," ##### "," # "," ##### "," ### "," ##### ", - " # # "," ## "," # # "," # "," ## "," # "," # "," # ", - " # ## "," # "," # "," # "," # # "," #### "," # "," # ", - " # # # "," # "," ## "," ## "," # # "," # "," #### "," # ", - " ## # "," # "," # "," # "," ##### "," # "," # # "," # ", - " # # "," # "," # "," # # "," # "," # # "," # # "," # ", - " ### "," ### "," ##### "," ### "," # "," ### "," ### "," # ", - " "," "," "," "," "," "," "," ", - " ### "," ### "," "," "," # "," "," # "," ### ", - " # # "," # # "," "," "," # "," "," # "," # # ", - " # # "," # # "," # "," # "," # "," ##### "," # "," # ", - " ### "," #### "," "," "," # "," "," # "," # ", - " # # "," # "," # "," # "," # "," ##### "," # "," # ", - " # # "," # "," "," # "," # "," "," # "," ", - " ### "," ### "," "," # "," # "," "," # "," # ", - " "," "," "," "," "," "," "," ", - " # "," "," # "," "," # "," "," ## "," ", - " # "," "," # "," "," # "," "," # # "," ", - " # "," ### "," #### "," #### "," #### "," ### "," # "," #### ", - " "," # "," # # "," # "," # # "," # # "," #### "," # # ", - " "," #### "," # # "," # "," # # "," ##### "," # "," # # ", - " "," # # "," # # "," # "," # # "," # "," # "," #### ", - " "," #### "," #### "," #### "," #### "," #### "," # "," # ", - " "," "," "," "," "," "," "," ### ", - " # "," # "," # "," # "," ## "," "," "," ", - " # "," "," "," # "," # "," "," "," ", - " #### "," ## "," ## "," # # "," # "," ## ## "," #### "," ### ", - " # # "," # "," # "," # # "," # "," # # # "," # # "," # # ", - " # # "," # "," # "," ### "," # "," # # # "," # # "," # # ", - " # # "," # "," # "," # # "," # "," # # # "," # # "," # # ", - " # # "," ### "," # # "," # # "," ### "," # # "," # # "," ### ", - " "," "," ## "," "," "," "," "," ", - " "," "," "," "," # "," "," "," ", - " "," "," "," "," # "," "," "," ", - " #### "," #### "," # ### "," #### "," #### "," # # "," # # "," # # ", - " # # "," # # "," ## "," # "," # "," # # "," # # "," # # ", - " # # "," # # "," # "," ### "," # "," # # "," # # "," # # # ", - " #### "," #### "," # "," # "," # # "," # ## "," # # "," # # # ", - " # "," # "," # "," #### "," ## "," ## # "," # "," ## ## ", - " # "," # "," "," "," "," "," "," ", - " "," "," "," ### "," # "," ### "," ## # "," ", - " "," "," "," ## "," # "," ## "," # ## "," # # # ", - " # # "," # # "," ##### "," ## "," # "," ## "," "," # # ", - " # # "," # # "," # "," ## "," # "," ## "," "," # # # ", - " # "," # # "," # "," ## "," # "," ## "," "," # # ", - " # # "," #### "," # "," ## "," # "," ## "," "," # # # ", - " # # "," # "," ##### "," ### "," # "," ### "," "," ", - " "," ### "," "," "," # "," "," "," ", - " # "," # "," "," #######"," "," #######"," ###"," ", - " # "," # "," "," # # "," #"," ###### "," ##"," ## ", - " ## ## "," ## ## "," # "," # # "," # "," ##### #"," ######"," ### ", - " #######"," # #"," ## "," # "," # # "," ## ##"," # ## "," ", - " ###### "," # # "," ### "," # "," # # "," # # ###"," # ####"," ### ", - " ###### "," # # "," #### "," # # "," # "," ## ####"," ## "," ## ", - " ######"," # # #"," ## ## "," # # # "," # "," ## ####"," ###### "," # ", - " ## ## "," ## ## "," # #"," #######"," "," #######"," # "," ###", - " # "," "," # "," # "," #######"," #"," ###### "," ## # ", - " # "," "," # "," ### "," "," #"," ###### "," ## ", - " # "," "," # "," # # # "," "," # #"," ###### "," ### ", - " #######"," "," # "," # # #"," "," ## #"," ###### "," ######", - " # "," "," # # #"," # "," "," #######"," ###### "," ### ", - " # "," "," # # # "," # "," "," ## "," ###### "," ## ", - " # "," "," ### "," # "," "," # "," ###### "," # ", - " "," # # # "," # "," # "," "," "," ###### "," #### ##", - " # ##"," #"," #"," "," # "," # "," # # # "," # # # #", - " ## "," # #"," # #"," "," # "," # "," # # # #"," # # # ", - " ### "," # "," ### "," "," # "," # "," # # # "," # # # #", - " ###### "," #######"," ##### "," #######"," # "," #######"," # # # #"," # # # ", - " ### "," ##### "," #######"," "," # "," # "," # # # "," # # # #", - " ## "," ### "," # "," "," # "," # "," # # # #"," # # # ", - " # "," # #"," # #"," "," # "," # "," # # # "," # # # #", - " ## ####"," #"," #"," "," #######"," "," # # # #"," # # # ", - " "," "," #"," # "," #######"," # # "," #######"," # ", - " ##### "," "," #"," ### "," "," # # "," #"," # ", - " # #","####### "," #"," ##### "," "," ### ###"," #"," # ", - " # "," #"," #"," #######"," "," "," ## #"," # ", - " # "," #"," #"," ##### "," "," ### ###"," ## #"," # ", - " # "," #"," #"," ### "," "," # # "," #"," # ", - " #######","########"," #"," # "," "," # # "," #"," # ", - " "," "," #"," "," #######"," "," #######"," # ", -}; - -#define STRINGS_PER_CHAR 8 -#define CHARS_PER_ROW 8 -#define STRINGS_PER_CHAR_ROW (STRINGS_PER_CHAR * CHARS_PER_ROW) - -void make_csbits (void) { - int i,j; - int szstrs = sizeof csstrs / sizeof csstrs[0]; - int numchars = szstrs / STRINGS_PER_CHAR; - - for (i = 0; i < numchars; ++i) { - int si = ((i / STRINGS_PER_CHAR) * STRINGS_PER_CHAR_ROW) + (i % CHARS_PER_ROW); - for (j = 0; j < STRINGS_PER_CHAR; ++j) - { - const char *sp = csstrs[si]; - unsigned char cb = 0; - - si += CHARS_PER_ROW; - - while (*sp) { - if (*sp++ != ' ') cb |= 0x80; - cb >>= 1; - } - - csbits[0][i][j] = cb; - } - } - - /* move mousetext */ - for (i = 96; i < 128; ++i) - for (j = 0; j < 8; ++j) - csbits[1][i-32][j] = csbits[0][i][j]; - - /* move lowercase */ - for (i = 64; i < 96; ++i) - for (j = 0; j < 8; ++j) - csbits[1][i+32][j] = csbits[1][i+160][j] = - csbits[0][i+160][j] = csbits[0][i][j]; - - /* move numbers */ - for (i = 32; i < 64; ++i) - for (j = 0; j < 8; ++j) - csbits[1][i][j] = csbits[1][i+128][j] = - csbits[0][i+64][j] = csbits[0][i+128][j] = csbits[0][i][j]; - - /* move uppercase */ - for (i = 0; i < 32; ++i) - for (j = 0; j < 8; ++j) - csbits[1][i][j] = csbits[1][i+128][j] = csbits[1][i+192][j] = - csbits[0][i+64][j] = csbits[0][i+128][j] = csbits[0][i+192][j] = csbits[0][i][j]; - - /* invert (skip mousetext) */ - for (i = 0; i < 128; ++i) - for (j = 0; j < 8; ++j) - { - csbits[0][i][j] ^= 0xFF; - if (i < 64 || i >= 96) - csbits[1][i][j] ^= 0xFF; - } -} - -#endif diff --git a/source/NTSC_CharSet.h b/source/NTSC_CharSet.h index faa3b1bb..3f549059 100644 --- a/source/NTSC_CharSet.h +++ b/source/NTSC_CharSet.h @@ -1,25 +1,4 @@ -/* -AppleWin : An Apple //e emulator for Windows - -Copyright (C) 2010-2011, William S Simms - -AppleWin is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -AppleWin is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with AppleWin; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef INCLUDED_CS_H -#define INCLUDED_CS_H +#pragma once typedef unsigned char (*csbits_t)[256][8]; @@ -30,6 +9,4 @@ extern unsigned char csbits_pravets82[1][256][8]; // Pravets 82 extern unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M extern unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C -void make_csbits (void); - -#endif +void make_csbits(void); From af196ac8ae84e628f5c35d8b6758b73dcd438ca0 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 26 Jul 2016 22:33:45 +0100 Subject: [PATCH 121/121] Tidy-up for full-screen vars --- source/Debugger/Debugger_Display.cpp | 12 +++--- source/Frame.cpp | 57 ++++++++++++++++++---------- source/Frame.h | 12 +----- source/Video.cpp | 26 ++++++------- 4 files changed, 57 insertions(+), 50 deletions(-) diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 980ff2c5..7bb24bfd 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -562,15 +562,15 @@ void StretchBltMemToFrameDC(void) int nViewportCX, nViewportCY; GetViewportCXCY(nViewportCX, nViewportCY); - FULLSCREEN_SCALE_TYPE xdest = g_win_fullscreen_offsetx; - FULLSCREEN_SCALE_TYPE ydest = g_win_fullscreen_offsety; - FULLSCREEN_SCALE_TYPE wdest = nViewportCX; - FULLSCREEN_SCALE_TYPE hdest = nViewportCY; + int xdest = GetFullScreenOffsetX(); + int ydest = GetFullScreenOffsetY(); + int wdest = nViewportCX; + int hdest = nViewportCY; BOOL bRes = StretchBlt( FrameGetDC(), // HDC hdcDest, - (int)xdest, (int)(ydest), // int nXOriginDest, int nYOriginDest, - (int)wdest, (int)(hdest), // int nWidthDest, int nHeightDest, + xdest, ydest, // int nXOriginDest, int nYOriginDest, + wdest, hdest, // int nWidthDest, int nHeightDest, GetDebuggerMemDC(), // HDC hdcSrc, 0, 0, // int nXOriginSrc, int nYOriginSrc, FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // int nWidthSrc, int nHeightSrc, diff --git a/source/Frame.cpp b/source/Frame.cpp index 6ea59283..7bca77d9 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -170,6 +170,19 @@ bool g_bScrollLock_FullSpeed = false; bool g_bFreshReset = false; static bool g_bFullScreen32Bit = true; +#if 0 // enable non-integral full-screen scaling +#define FULLSCREEN_SCALE_TYPE float +#else +#define FULLSCREEN_SCALE_TYPE int +#endif + +static RECT g_main_window_saved_rect; +static int g_main_window_saved_style; +static int g_main_window_saved_exstyle; +static FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale = 1; +static int g_win_fullscreen_offsetx = 0; +static int g_win_fullscreen_offsety = 0; + // __ Prototypes __________________________________________________________________________________ static void DrawCrosshairs (int x, int y); static void FrameSetCursorPosByMousePos(int x, int y, int dx, int dy, bool bLeavingAppleScreen); @@ -478,10 +491,10 @@ static void DrawCrosshairs (int x, int y) { while (loop--) { RECT rect = {0,0,5,5}; switch (loop) { - case 0: OffsetRect(&rect, g_win_fullscreen_offsetx+lastx-2, g_win_fullscreen_offsety+viewporty-5); break; - case 1: OffsetRect(&rect, g_win_fullscreen_offsetx+lastx-2, g_win_fullscreen_offsety+viewporty+g_nViewportCY); break; - case 2: OffsetRect(&rect, g_win_fullscreen_offsetx+viewportx-5, g_win_fullscreen_offsety+lasty-2); break; - case 3: OffsetRect(&rect, g_win_fullscreen_offsetx+viewportx+g_nViewportCX, g_win_fullscreen_offsety+lasty-2); break; + case 0: OffsetRect(&rect, GetFullScreenOffsetX()+lastx-2, GetFullScreenOffsetY()+viewporty-5); break; + case 1: OffsetRect(&rect, GetFullScreenOffsetX()+lastx-2, GetFullScreenOffsetY()+viewporty+g_nViewportCY); break; + case 2: OffsetRect(&rect, GetFullScreenOffsetX()+viewportx-5, GetFullScreenOffsetY()+lasty-2); break; + case 3: OffsetRect(&rect, GetFullScreenOffsetX()+viewportx+g_nViewportCX, GetFullScreenOffsetY()+lasty-2); break; } FillRect(dc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); } @@ -521,14 +534,14 @@ static void DrawCrosshairs (int x, int y) { SelectObject(dc,GetStockObject(WHITE_PEN)); else SelectObject(dc,GetStockObject(BLACK_PEN)); - LINE(g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty-5, - g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty); - LINE(g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty+g_nViewportCY+4, - g_win_fullscreen_offsetx+x+loop-2, g_win_fullscreen_offsety+viewporty+g_nViewportCY-1); - LINE(g_win_fullscreen_offsetx+viewportx-5, g_win_fullscreen_offsety+y+loop-2, - g_win_fullscreen_offsetx+viewportx, g_win_fullscreen_offsety+y+loop-2); - LINE(g_win_fullscreen_offsetx+viewportx+g_nViewportCX+4, g_win_fullscreen_offsety+y+loop-2, - g_win_fullscreen_offsetx+viewportx+g_nViewportCX-1, g_win_fullscreen_offsety+y+loop-2); + LINE(GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty-5, + GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty); + LINE(GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty+g_nViewportCY+4, + GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty+g_nViewportCY-1); + LINE(GetFullScreenOffsetX()+viewportx-5, GetFullScreenOffsetY()+y+loop-2, + GetFullScreenOffsetX()+viewportx, GetFullScreenOffsetY()+y+loop-2); + LINE(GetFullScreenOffsetX()+viewportx+g_nViewportCX+4, GetFullScreenOffsetY()+y+loop-2, + GetFullScreenOffsetX()+viewportx+g_nViewportCX-1, GetFullScreenOffsetY()+y+loop-2); } } else @@ -2088,13 +2101,15 @@ void SetFullScreen32Bit(bool b32Bit) g_bFullScreen32Bit = b32Bit; } -// TODO: Put this stuff in a header / somewhere sensible -RECT g_main_window_saved_rect; -int g_main_window_saved_style; -int g_main_window_saved_exstyle; -FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale = 1; -int g_win_fullscreen_offsetx = 0; -int g_win_fullscreen_offsety = 0; +int GetFullScreenOffsetX(void) +{ + return g_win_fullscreen_offsetx; +} + +int GetFullScreenOffsetY(void) +{ + return g_win_fullscreen_offsety; +} void SetFullScreenMode () { @@ -2144,8 +2159,8 @@ void SetFullScreenMode () // FS: desktop SetViewportScale(g_win_fullscreen_scale, true); - buttonx = g_win_fullscreen_offsetx + g_nViewportCX + VIEWPORTX*2; - buttony = g_win_fullscreen_offsety; + buttonx = GetFullScreenOffsetX() + g_nViewportCX + VIEWPORTX*2; + buttony = GetFullScreenOffsetY(); viewportx = VIEWPORTX; viewporty = VIEWPORTY; #endif diff --git a/source/Frame.h b/source/Frame.h index 7ded8b69..2c68c879 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -52,16 +52,6 @@ extern int g_nCharsetType; -#if 0 // enable non-integral full-screen scaling -#define FULLSCREEN_SCALE_TYPE float -#else -#define FULLSCREEN_SCALE_TYPE int -#endif -extern FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale; -extern int g_win_fullscreen_offsetx; -extern int g_win_fullscreen_offsety; - - // Prototypes void CtrlReset(); @@ -89,3 +79,5 @@ extern int g_win_fullscreen_offsety; WPARAM wparam, LPARAM lparam ); + int GetFullScreenOffsetX(void); + int GetFullScreenOffsetY(void); diff --git a/source/Video.cpp b/source/Video.cpp index b2f256dd..9d22835b 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -994,8 +994,8 @@ void VideoDisplayLogo () nLogoX = 0; nLogoY = 0; #else - nLogoX += g_win_fullscreen_offsetx; - nLogoY += g_win_fullscreen_offsety; + nLogoX += GetFullScreenOffsetX(); + nLogoY += GetFullScreenOffsetY(); #endif } VideoDrawLogoBitmap( hFrameDC, nLogoX, nLogoY, bm.bmWidth, bm.bmHeight, scale ); @@ -1014,7 +1014,7 @@ void VideoDisplayLogo () char szVersion[ 64 ] = ""; sprintf( szVersion, "Version %s", VERSIONSTRING ); - int xoff = g_win_fullscreen_offsetx, yoff = g_win_fullscreen_offsety; + int xoff = GetFullScreenOffsetX(), yoff = GetFullScreenOffsetY(); #define DRAWVERSION(x,y,c) \ SetTextColor(hFrameDC,c); \ @@ -1068,15 +1068,15 @@ void VideoDisplayLogo () // sprintf( szVersion, "NTSC Alpha v17 BMP Palette" ); sprintf( szVersion, "NTSC Alpha v18" ); - xoff = -g_nViewportCX + g_nViewportCX/6 + g_win_fullscreen_offsetx; - yoff = -g_nViewportCY/16 + g_win_fullscreen_offsety; + xoff = -g_nViewportCX + g_nViewportCX/6 + GetFullScreenOffsetX(); + yoff = -g_nViewportCY/16 + GetFullScreenOffsetY(); DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); sprintf( szVersion, "Blurry 80-col Text" ); - xoff = -g_nViewportCX + g_nViewportCX/6 + g_win_fullscreen_offsetx; - yoff = +g_nViewportCY/16 + g_win_fullscreen_offsety; + xoff = -g_nViewportCX + g_nViewportCX/6 + GetFullScreenOffsetX(); + yoff = +g_nViewportCY/16 + GetFullScreenOffsetY(); DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00)); DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF)); @@ -1266,16 +1266,16 @@ void VideoRefreshScreen ( int bVideoModeFlags, UINT uDelayRefresh /* =0 */ ) ySrc -= 1; } - FULLSCREEN_SCALE_TYPE xdest = g_win_fullscreen_offsetx; - FULLSCREEN_SCALE_TYPE ydest = g_win_fullscreen_offsety; - FULLSCREEN_SCALE_TYPE wdest = g_nViewportCX /** g_win_fullscreen_scale*/; - FULLSCREEN_SCALE_TYPE hdest = g_nViewportCY /** g_win_fullscreen_scale*/; + int xdest = GetFullScreenOffsetX(); + int ydest = GetFullScreenOffsetY(); + int wdest = g_nViewportCX; + int hdest = g_nViewportCY; SetStretchBltMode(hFrameDC, COLORONCOLOR); StretchBlt( hFrameDC, - (int)xdest, (int)ydest, - (int)wdest, (int)hdest, + xdest, ydest, + wdest, hdest, g_hDeviceDC, xSrc, ySrc, FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H,